[Erp5-report] r14439 - in /erp5/trunk/products/ERP5SyncML: ./ Conduit/ dtml/ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Thu May 10 14:13:53 CEST 2007
Author: seb
Date: Thu May 10 14:13:52 2007
New Revision: 14439
URL: http://svn.erp5.org?rev=14439&view=rev
Log:
fabien finished to implement authentication, and he added tests for it
Modified:
erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py
erp5/trunk/products/ERP5SyncML/Publication.py
erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
erp5/trunk/products/ERP5SyncML/Subscription.py
erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py
erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml
erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml
erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml
erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml
erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
Modified: erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py (original)
+++ erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py Thu May 10 14:13:52 2007
@@ -129,11 +129,6 @@
xml = self.convertToXml(xml)
LOG('addNode',0,'xml_reconstitued: %s' % str(xml))
# In the case where this new node is a object to add
- LOG('addNode',0,'object.id: %s' % object.getId())
- LOG('addNode',0,'xml.nodeName: %s' % xml.nodeName)
- LOG('addNode',0,'getSubObjectDepth: %i' % self.getSubObjectDepth(xml))
- LOG('addNode',0,'isHistoryAdd: %i' % self.isHistoryAdd(xml))
- LOG('addNode xml',0,repr(xml.toxml()))
if xml.nodeName in self.XUPDATE_INSERT_OR_ADD and self.getSubObjectDepth(xml)==0:
if self.isHistoryAdd(xml)!=-1: # bad hack XXX to be removed
for element in self.getXupdateElementList(xml):
@@ -216,7 +211,6 @@
object_id = self.getAttribute(xml,'id')
elif self.getSubObjectDepth(xml)==1:
object_id = self.getSubObjectId(xml)
- #LOG('ERP5Conduit',0,'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml))
elif self.getSubObjectDepth(xml)==2:
# we have to call delete node on a subsubobject
sub_object_id = self.getSubObjectId(xml)
@@ -706,14 +700,11 @@
for subnode in self.getElementNodeList(xml):
if not(subnode.nodeName in self.NOT_EDITABLE_PROPERTY):
keyword_type = self.getPropertyType(subnode)
- LOG('newObject',0,str(subnode.childNodes))
# This is the case where the property is a list
keyword=str(subnode.nodeName)
if len(subnode.childNodes) > 0: # We check that this tag is not empty
data = subnode.childNodes[0].data
args[keyword]=data
- LOG('newObject',0,'keyword: %s' % str(keyword))
- LOG('newObject',0,'keywordtype: %s' % str(keyword_type))
#if args.has_key(keyword):
# LOG('newObject',0,'data: %s' % str(args[keyword]))
if args.has_key(keyword):
@@ -722,8 +713,6 @@
self.addNode(object=object,xml=subnode, force=1)
# We should first edit the object
args = self.getFormatedArgs(args=args)
- LOG('newObject',0,"object.getphyspath: %s" % str(object.getPhysicalPath()))
- LOG('newObject',0,"args: %s" % str(args))
# edit the object with a dictionnary of arguments,
# like {"telephone_number":"02-5648"}
#object._edit(**args)
@@ -885,7 +874,6 @@
dict_list = map(lambda x:x.split(':'),data[1:-1].split(','))
data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list)
data = dict(data)
- LOG('convertXmlValue',0,'data: %s' % str(data))
return data
# XXX is it the right place ? It should be in XupdateUtils, but here we
@@ -997,7 +985,6 @@
add_action = self.isWorkflowActionAddable(object=object,
status=status,wf_tool=wf_tool,
wf_id=wf_id,xml=xml)
- #LOG('addNode, workflow_history wf_conflict_list:',0,wf_conflict_list)
LOG('addNode, workflow_history add_action:',0,add_action)
if add_action and not simulate:
LOG('addNode, setting status:',0,'ok')
Modified: erp5/trunk/products/ERP5SyncML/Publication.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Publication.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Publication.py (original)
+++ erp5/trunk/products/ERP5SyncML/Publication.py Thu May 10 14:13:52 2007
@@ -152,7 +152,9 @@
constructors = (addPublication,)
# Constructor
- def __init__(self, id, title, publication_url, destination_path, query, xml_mapping, conduit, gpg_key):
+ def __init__(self, id, title, publication_url, destination_path,
+ query, xml_mapping, conduit, gpg_key, auth_required=False,
+ authentication_format='', authentication_type=''):
"""
constructor
"""
@@ -169,6 +171,9 @@
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
+ self.auth_required = auth_required
+ self.authentication_format = authentication_format
+ self.authentication_type = authentication_type
def getPublicationUrl(self):
"""
@@ -188,6 +193,42 @@
return the publication url
"""
self.publication_url = publication_url
+
+ def isAuthenticationRequired(self):
+ """
+ return False if authentication not required, True else
+ """
+ return getattr(self, 'auth_required', False)
+
+ def setAuthentication(self, auth):
+ """
+ set the value of the authentication requirement
+ """
+ self.auth_required = auth
+
+ def getAuthenticationFormat(self):
+ """
+ return the format of authentication
+ """
+ return getattr(self, 'authentication_format', '')
+
+ def getAuthenticationType(self):
+ """
+ return the type of authentication
+ """
+ return getattr(self, 'authentication_type', '')
+
+ def setAuthenticationFormat(self, authentication_format):
+ """
+ set the format of authentication
+ """
+ self.authentication_format = authentication_format
+
+ def setAuthenticationType(self, authentication_type):
+ """
+ set the type of authentication
+ """
+ self.authentication_type = authentication_type
def addSubscriber(self, subscriber):
"""
Modified: erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py (original)
+++ erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py Thu May 10 14:13:52 2007
@@ -34,6 +34,10 @@
from XMLSyncUtils import XMLSyncUtils
from Conduit.ERP5Conduit import ERP5Conduit
from Products.CMFCore.utils import getToolByName
+from Products.ERP5Security.ERP5UserManager import ERP5UserManager
+from Products.PluggableAuthService.interfaces.plugins import\
+ IAuthenticationPlugin
+from AccessControl.SecurityManagement import newSecurityManager
import commands
from zLOG import LOG
@@ -43,17 +47,19 @@
"""
def PubSyncInit(self, publication=None, xml_client=None, subscriber=None,
- sync_type=None, auth_required=0):
+ sync_type=None):
"""
Read the client xml message
Send the first XML message from the server
"""
LOG('PubSyncInit',0,'Starting... publication: %s' % str(publication))
-
+
#the session id is set at the same value of those of the client
subscriber.setSessionId(self.getSessionId(xml_client))
- # for a new session, the message Id must be reset
- subscriber.resetMessageId()
+ #same for the message id
+ subscriber.setMessageId(self.getMessageId(xml_client))
+ #at the begining of the synchronization the subscriber is not authenticated
+ subscriber.setAuthenticated(False)
#the last_message_id is 1 because the message that
#we are about to send is the message 1
subscriber.initLastMessageId(1)
@@ -67,33 +73,83 @@
alert_code = self.getAlertCode(xml_client)
cred = self.checkCred(xml_client)
#XXX this is in developement, it's just for tests
- if not cred and auth_required:
- LOG('PubSyncInit',0,'authentication required')
- # Prepare the xml message for the Sync initialization package
- cmd_id = 1 # specifies a SyncML message-unique command identifier
- xml_list = []
- xml = xml_list.append
- xml('<SyncML>\n')
- # syncml header
- xml(self.SyncMLHeader(subscriber.getSessionId(),
- subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(),
- publication.getPublicationUrl()))
- # syncml body
- xml(' <SyncBody>\n')
- # chal message
- xml(self.SyncMLChal(cmd_id, "SyncHdr", publication.getPublicationUrl(),
- subscriber.getSubscriptionUrl(), "b64", "syncml:auth-basic",
- self.UNAUTHORIZED))
- cmd_id += 1
-
- xml(' </SyncBody>\n')
-
- xml('</SyncML>\n')
- xml_a = ''.join(xml_list)
-
- self.sendResponse(from_url=publication.getPublicationUrl(),
- to_url=subscriber.getSubscriptionUrl(),sync_id=publication.getTitle(),
- xml=xml_a,domain=publication)
+ if publication.isAuthenticationRequired():
+ if not cred:
+ LOG('PubSyncInit',0,'authentication required')
+ # Prepare the xml message for the Sync initialization package
+ cmd_id = 1 # specifies a SyncML message-unique command identifier
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
+ # syncml header
+ xml(self.SyncMLHeader(subscriber.getSessionId(),
+ subscriber.getMessageId(), subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl()))
+ # syncml body
+ xml(' <SyncBody>\n')
+ # chal message
+ xml(self.SyncMLChal(cmd_id, "SyncHdr",
+ publication.getPublicationUrl(), subscriber.getSubscriptionUrl(),
+ publication.getAuthenticationFormat(),
+ publication.getAuthenticationType(), self.AUTH_REQUIRED))
+ cmd_id += 1
+
+ xml(' </SyncBody>\n')
+
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
+
+ self.sendResponse(from_url=publication.getPublicationUrl(),
+ to_url=subscriber.getSubscriptionUrl(),
+ sync_id=publication.getTitle(), xml=xml_a, domain=publication)
+
+ else:#(if the subscriber begin the session with a cred) -> to be tested
+ (authentication_format, authentication_type, data) = self.getCred(xml_client)
+ #at the begining, the code is initialised at UNAUTHORIZED
+ auth_code=self.UNAUTHORIZED
+
+ if authentication_format == publication.getAuthenticationFormat():
+ if authentication_type == publication.getAuthenticationType():
+ decoded = subscriber.decode(authentication_format, data)
+ if decoded not in ('', None) and decoded.__contains__(':'):
+ (login, password) = decoded.split(':')
+ uf = self.getPortalObject().acl_users
+ for plugin_name, plugin in uf._getOb('plugins').listPlugins(
+ IAuthenticationPlugin ):
+ if plugin.authenticateCredentials(
+ {'login':login, 'password':password}) is not None:
+ subscriber.setAuthenticated(True)
+ auth_code=self.AUTH_ACCEPTED
+ #here we must log in with the user authenticated :
+ user = uf.getUserById(login).__of__(uf)
+ newSecurityManager(None, user)
+ subscriber.setUser(login)
+ break
+ #in all others cases, the auth_code is set to UNAUTHORIZED
+
+
+ # Prepare the xml message for the Sync initialization package
+ cmd_id = 1 # specifies a SyncML message-unique command identifier
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
+ # syncml header
+ xml(self.SyncMLHeader(subscriber.getSessionId(),
+ subscriber.getMessageId(),
+ subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl()))
+ # syncml body
+ xml(' <SyncBody>\n')
+ xml(self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl(), auth_code))
+ xml(' </SyncBody>\n')
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
+
+ self.sendResponse(from_url=publication.getPublicationUrl(),
+ to_url=subscriber.getSubscriptionUrl(),
+ sync_id=publication.getTitle(), xml=xml_a, domain=publication)
+
else :
# If slow sync, then resend everything
if alert_code == self.SLOW_SYNC:
@@ -103,8 +159,7 @@
# Check if the last time synchronization is the same as the client one
mess='\nsubscriber.getNextAnchor:\t%s\nsubscriber.getLastAnchor:\t%s\
- \nlast_anchor:\t\t\t%s\nnext_anchor:\t\t\t%s' % (subscriber.getNextAnchor(),
- subscriber.getLastAnchor(), last_anchor, next_anchor)
+ \nlast_anchor:\t\t\t%s\nnext_anchor:\t\t\t%s' % (subscriber.getNextAnchor(), subscriber.getLastAnchor(), last_anchor, next_anchor)
LOG('PubSyncInit',0,mess)
if subscriber.getNextAnchor() != last_anchor:
@@ -112,8 +167,8 @@
LOG('PubSyncInit',0,'anchor null')
raise ValueError, "Sorry, the anchor was null"
else:
- message = "bad anchors in PubSyncInit! " + subscriber.getNextAnchor() + \
- " and " + last_anchor
+ message = "bad anchors in PubSyncInit! " + \
+ subscriber.getNextAnchor() + " and " + last_anchor
LOG('PubSyncInit',0,message)
else:
subscriber.setNextAnchor(next_anchor)
@@ -123,8 +178,7 @@
# We have started the sync from the server (may be for a conflict resolution)
pass
- if alert is not None and auth_required==0:
- #if 1:
+ if alert is not None and not publication.isAuthenticationRequired():
# Prepare the xml message for the Sync initialization package
cmd_id = 1 # specifies a SyncML message-unique command identifier
xml_list = []
@@ -203,7 +257,15 @@
result = self.PubSyncInit(publication=publication,
xml_client=xml_client, subscriber=subscriber, sync_type=alert_code)
else:
- result = self.PubSyncModif(publication, xml_client)
+ #we log the user authenticated to do the synchronization with him
+ if publication.isAuthenticationRequired():
+ if subscriber.isAuthenticated():
+ uf = self.getPortalObject().acl_users
+ user = uf.getUserById(subscriber.getUser()).__of__(uf)
+ newSecurityManager(None, user)
+ result = self.PubSyncModif(publication, xml_client)
+ else:
+ result = self.PubSyncModif(publication, xml_client)
elif subscriber is not None:
# This looks like we are starting a synchronization after
# a conflict resolution by the user
Modified: erp5/trunk/products/ERP5SyncML/Subscription.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Subscription.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Subscription.py (original)
+++ erp5/trunk/products/ERP5SyncML/Subscription.py Thu May 10 14:13:52 2007
@@ -41,6 +41,11 @@
import md5
+try:
+ from base64 import b64encode, b64decode
+except ImportError:
+ from base64 import encodestring as b64encode, decodestring as b64decode
+
#class Conflict(SyncCode, Implicit):
class Conflict(SyncCode, Base):
"""
@@ -53,8 +58,8 @@
isIndexable = 0
isPortalContent = 0 # Make sure RAD generated accessors at the class level
- def __init__(self, object_path=None, keyword=None, xupdate=None, publisher_value=None,\
- subscriber_value=None, subscriber=None):
+ def __init__(self, object_path=None, keyword=None, xupdate=None,
+ publisher_value=None, subscriber_value=None, subscriber=None):
self.object_path=object_path
self.keyword = keyword
self.setLocalValue(publisher_value)
@@ -614,8 +619,8 @@
isPortalContent = 1
isRADContent = 1
icon = None
-
isIndexable = 0
+ user = None
# Declarative properties
property_sheets = ( PropertySheet.Base
@@ -635,7 +640,8 @@
)
# Constructor
- def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, conduit, gpg_key):
+ def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, conduit, gpg_key, login, password,
+ authentication_format='', authentication_type=''):
"""
We need to create a dictionnary of
signatures of documents which belong to the synchronisation
@@ -652,6 +658,10 @@
#self.signatures = PersistentMapping()
self.last_anchor = '00000000T000000Z'
self.next_anchor = '00000000T000000Z'
+ self.login=login
+ self.password=password
+ self.authentication_format=authentication_format
+ self.authentication_type=authentication_type
self.domain_type = self.SUB
self.gpg_key = gpg_key
self.setGidGenerator(None)
@@ -714,28 +724,28 @@
We will see if the last session id was the same
wich means that the same message was sent again
- return 1 if the session id was not seen, 0 if already seen
+ return True if the session id was not seen, False if already seen
"""
last_session_id = getattr(self,'last_session_id',None)
if last_session_id == session_id:
- return 0
+ return False
self.last_session_id = session_id
- return 1
+ return True
def checkCorrectRemoteMessageId(self, message_id):
"""
We will see if the last message id was the same
wich means that the same message was sent again
- return 1 if the message id was not seen, 0 if already seen
+ return True if the message id was not seen, False if already seen
"""
last_message_id = getattr(self,'last_message_id',None)
# LOG('checkCorrectRemoteMessageId last_message_id =',0,last_message_id)
# LOG('checkCorrectRemoteMessageId message_id =',0,message_id)
if last_message_id == message_id:
- return 0
+ return False
self.last_message_id = message_id
- return 1
+ return True
def initLastMessageId(self, last_message_id=None):
"""
@@ -872,25 +882,74 @@
"""
return self.gid_generator
+ def getLogin(self):
+ """
+ This method return the login of this subscription
+ """
+ return getattr(self, 'login', '')
+
+ def setLogin(self, new_login):
+ """
+ set the login at new_login
+ """
+ self.login=new_login
+
+ def getPassword(self):
+ """
+ This method return the password of this subscription
+ """
+ return getattr(self, 'password', '')
+
+ def setPassword(self, new_password):
+ """
+ set the password at new_password
+ """
+ self.password=new_password
+
+
+ def setAuthentication(self, auth):
+ """
+ set the value of the authentication requirement
+ """
+ self.auth_required = auth
+
+ def getAuthenticationFormat(self):
+ """
+ return the format of authentication
+ """
+ return getattr(self, 'authentication_format', '')
+
+ def getAuthenticationType(self):
+ """
+ return the type of authentication
+ """
+ return getattr(self, 'authentication_type', '')
+
+ def setAuthenticationFormat(self, authentication_format):
+ """
+ set the format of authentication
+ """
+ self.authentication_format = authentication_format
+
+ def setAuthenticationType(self, authentication_type):
+ """
+ set the type of authentication
+ """
+ self.authentication_type = authentication_type
+
def getGidFromObject(self, object):
"""
"""
o_base = aq_base(object)
o_gid = None
- # LOG('getGidFromObject',0,'gidgenerator : _%s_' % repr(self.getGidGenerator()))
gid_gen = self.getGidGenerator()
if callable(gid_gen):
- # LOG('getGidFromObject gid_generator',0,'is callable')
o_gid=gid_gen(object)
- # LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
elif getattr(o_base, gid_gen, None) is not None:
- # LOG('getGidFromObject',0,'there is the gid generator on o_base')
generator = getattr(object, gid_gen)
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant
- # LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
elif gid_gen is not None:
# It might be a script python
- # LOG('getGidFromObject',0,'there is the gid generator')
generator = getattr(object,gid_gen)
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant
# LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
@@ -911,7 +970,6 @@
# LOG('getObjectFromGid oject_list',0,object_list)
if signature is not None and signature.getId() is not None:
o_id = signature.getId()
- # LOG('getObjectFromGid o_id',0,o_id)
o = None
try:
o = destination._getOb(o_id)
@@ -920,7 +978,6 @@
if o is not None and o in object_list:
return o
for o in object_list:
- # LOG('getObjectFromGid',0,'working on : %s' % repr(o))
o_gid = self.getGidFromObject(o)
if o_gid == gid:
return o
@@ -1073,6 +1130,12 @@
set the message id to 0
"""
self.message_id = 0
+
+ def setMessageId(self, message_id):
+ """
+ set the message id to message_id
+ """
+ self.message_id = message_id
def getLastAnchor(self):
"""
@@ -1230,3 +1293,67 @@
o.setTempXML(None)
self.setRemainingObjectPathList(None)
+
+ def isAuthenticated(self):
+ """
+ return True if the subscriber is authenticated for this session, False
+ in other case
+ """
+ return self.is_authenticated
+
+ def setAuthenticated(self, value):
+ """
+ set at True or False the value of is_authenticated is the subscriber
+ is authenticated for this session or not
+ """
+ self.is_authenticated = value
+
+ def encode(self, format, string_to_encode):
+ """
+ return the string_to_encode encoded with format format
+ """
+ if format in ('', None):
+ return string_to_encode
+ if format == 'b64':
+ return b64encode(string_to_encode)
+ #elif format is .... put here the other formats
+ else:#if there is no format corresponding with format, raise an error
+ LOG('encode : unknown or not implemented format :', 0, format)
+ raise ValueError, "Sorry, the format %s is unknow or not implemented" % format
+
+ def decode(self, format, string_to_decode):
+ """
+ return the string_to_decode decoded with format format
+ """
+ string_to_decode = string_to_decode.encode('utf-8')
+ if format in ('', None):
+ return string_to_decode
+ if format == 'b64':
+ return b64decode(string_to_decode)
+ #elif format is .... put here the other formats
+ else:#if there is no format corresponding with format, raise an error
+ LOG('decode : unknown or not implemented format :', 0, format)
+ raise ValueError, "Sorry, the format %s is unknow or not implemented" % format
+
+ def isDecodeEncodeTheSame(self, string_encoded, string_decoded, format):
+ """
+ return True if the string_encoded is equal to string_decoded encoded
+ in format
+ """
+ isTheSame=False
+ if self.encode(format, string_decoded) == string_encoded:
+ isTheSame=True
+ return isTheSame
+
+
+ def setUser(self, user):
+ """
+ save the user logged in to log him on each transaction
+ """
+ self.user=user
+
+ def getUser(self):
+ """
+ retrun the user logged in
+ """
+ return self.user
Modified: erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py (original)
+++ erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py Thu May 10 14:13:52 2007
@@ -44,6 +44,8 @@
"""
LOG('SubSyncInit',0,'starting....')
cmd_id = 1 # specifies a SyncML message-unique command identifier
+ subscription.NewAnchor()
+ subscription.initLastMessageId()
xml_list = []
xml = xml_list.append
xml('<SyncML>\n')
@@ -54,8 +56,6 @@
# syncml body
xml(' <SyncBody>\n')
- subscription.NewAnchor()
- subscription.initLastMessageId()
# We have to set every object as NOT_SYNCHRONIZED
subscription.startSynchronization()
@@ -100,13 +100,74 @@
xml_client = msg
if isinstance(xml_client, str) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client)
- response = self.SubSyncModif(self.getSubscription(id),xml_client)
+ next_status = self.getNextSyncBodyStatus(xml_client, None)
+ #LOG('readResponse, next status :',0,next_status)
+ if next_status is not None:
+ status_code = self.getStatusCode(next_status)
+ #LOG('readResponse status code :',0,status_code)
+ if status_code == self.AUTH_REQUIRED:
+ #LOG('readResponse', 0, 'Authentication required')
+ response = self.SubSyncCred(id, xml_client)
+ elif status_code == self.UNAUTHORIZED:
+ #LOG('readResponse', 0, 'Bad authentication')
+ return {'has_response':0,'xml':xml_client}
+ else:
+ response = self.SubSyncModif(self.getSubscription(id), xml_client)
+ else:
+ response = self.SubSyncModif(self.getSubscription(id), xml_client)
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
else:
return response
+
+ def SubSyncCred (self, id, msg=None, RESPONSE=None):
+ """
+ This method send crendentials
+ """
+
+ LOG('SubSyncCred',0,'starting... id: %s' % str(id))
+ LOG('SubSyncCred',0,'starting... msg: %s' % str(msg))
+
+ cmd_id = 1 # specifies a SyncML message-unique command identifier
+ subscription = self.getSubscription(id)
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
+ # syncml header
+ data = "%s:%s" % (subscription.getLogin(), subscription.getPassword())
+ data=subscription.encode(subscription.getAuthenticationFormat(), data)
+ xml(self.SyncMLHeader(subscription.getSessionId(),
+ subscription.incrementMessageId(), subscription.getPublicationUrl(),
+ subscription.getSubscriptionUrl(), dataCred=data,
+ authentication_format=subscription.getAuthenticationFormat(),
+ authentication_type=subscription.getAuthenticationType()))
+
+ # syncml body
+ xml(' <SyncBody>\n')
+
+ # alert message
+ xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
+ subscription.getPublicationUrl(),
+ subscription.getDestinationPath(),
+ subscription.getLastAnchor(),
+ subscription.getNextAnchor()))
+ cmd_id += 1
+
+ xml(' <Put>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ cmd_id += 1
+ xml(' </Put>\n')
+ xml(' </SyncBody>\n')
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
+
+ self.sendResponse(from_url=subscription.subscription_url,
+ to_url=subscription.publication_url, sync_id=subscription.getTitle(),
+ xml=xml_a,domain=subscription)
+
+ return {'has_response':1,'xml':xml_a}
def SubSyncModif(self, subscription, xml_client):
"""
Modified: erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SynchronizationTool.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SynchronizationTool.py (original)
+++ erp5/trunk/products/ERP5SyncML/SynchronizationTool.py Thu May 10 14:13:52 2007
@@ -62,8 +62,8 @@
-class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronization,
- UniqueObject, Folder):
+class SynchronizationTool( SubscriptionSynchronization,
+ PublicationSynchronization, UniqueObject, Folder):
"""
This tool implements the synchronization algorithm
@@ -159,9 +159,11 @@
+ '?manage_tabs_message=Tool+updated.'
)
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_addPublication')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_addPublication')
def manage_addPublication(self, title, publication_url, destination_path,
- query, xml_mapping, conduit, gpg_key, RESPONSE=None):
+ query, xml_mapping, conduit, gpg_key, auth_required=0,
+ authentication_format='', authentication_type='', RESPONSE=None):
"""
create a new publication
"""
@@ -171,7 +173,8 @@
folder = self.getObjectContainer()
new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path,
- query, xml_mapping, conduit, gpg_key)
+ query, xml_mapping, conduit, gpg_key, auth_required,
+ authentication_format, authentication_type)
folder._setObject( new_id, pub )
#if len(self.list_publications) == 0:
# self.list_publications = PersistentMapping()
@@ -179,9 +182,12 @@
if RESPONSE is not None:
RESPONSE.redirect('managePublications')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_addSubscription')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url,
- destination_path, query, xml_mapping, conduit, gpg_key, RESPONSE=None):
+ destination_path, query, xml_mapping, conduit, gpg_key,
+ login=None, password=None, authentication_format='',
+ authentication_type='',RESPONSE=None):
"""
XXX should be renamed as addSubscription
create a new subscription
@@ -192,7 +198,9 @@
folder = self.getObjectContainer()
new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url,
- destination_path, query, xml_mapping, conduit, gpg_key)
+ destination_path, query, xml_mapping, conduit, gpg_key,
+ login, password, authentication_format,
+ authentication_type)
folder._setObject( new_id, sub )
#if len(self.list_subscriptions) == 0:
# self.list_subscriptions = PersistentMapping()
@@ -200,10 +208,12 @@
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_editPublication')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, id_generator,
- gid_generator, RESPONSE=None):
+ gid_generator, auth_required=0, authentication_format='',
+ authentication_type='', RESPONSE=None):
"""
modify a publication
"""
@@ -217,13 +227,19 @@
pub.setGPGKey(gpg_key)
pub.setIdGenerator(id_generator)
pub.setGidGenerator(gid_generator)
+ pub.setAuthentication(auth_required)
+ pub.setAuthenticationFormat(authentication_format)
+ pub.setAuthenticationType(authentication_type)
+
if RESPONSE is not None:
RESPONSE.redirect('managePublications')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_editSubscription')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url,
- destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
- gid_generator, RESPONSE=None):
+ destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
+ gid_generator,login='', password='', authentication_format='',
+ authentication_type='', RESPONSE=None):
"""
modify a subscription
"""
@@ -238,10 +254,15 @@
sub.setSubscriptionUrl(subscription_url)
sub.setIdGenerator(id_generator)
sub.setGidGenerator(gid_generator)
+ sub.setLogin(login)
+ sub.setPassword(password)
+ sub.setAuthenticationFormat(authentication_format)
+ sub.setAuthenticationType(authentication_type)
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_deletePublication')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_deletePublication')
def manage_deletePublication(self, title, RESPONSE=None):
"""
delete a publication
@@ -252,7 +273,8 @@
if RESPONSE is not None:
RESPONSE.redirect('managePublications')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_deleteSubscription')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_deleteSubscription')
def manage_deleteSubscription(self, title, RESPONSE=None):
"""
delete a subscription
@@ -263,7 +285,8 @@
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetPublication')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_resetPublication')
def manage_resetPublication(self, title, RESPONSE=None):
"""
reset a publication
@@ -273,7 +296,8 @@
if RESPONSE is not None:
RESPONSE.redirect('managePublications')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetSubscription')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_resetSubscription')
def manage_resetSubscription(self, title, RESPONSE=None):
"""
reset a subscription
@@ -284,7 +308,8 @@
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
- security.declareProtected(Permissions.ModifyPortalContent, 'manage_syncSubscription')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manage_syncSubscription')
def manage_syncSubscription(self, title, RESPONSE=None):
"""
reset a subscription
@@ -293,7 +318,8 @@
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
- security.declareProtected(Permissions.AccessContentsInformation,'getPublicationList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getPublicationList')
def getPublicationList(self):
"""
Return a list of publications
@@ -303,7 +329,8 @@
object_list = filter(lambda x: x.id.find('pub')==0,object_list)
return object_list
- security.declareProtected(Permissions.AccessContentsInformation,'getPublication')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getPublication')
def getPublication(self, title):
"""
Return the publications with this id
@@ -313,7 +340,8 @@
return p
return None
- security.declareProtected(Permissions.AccessContentsInformation,'getObjectContainer')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getObjectContainer')
def getObjectContainer(self):
"""
this returns the external mount point if there is one
@@ -325,7 +353,8 @@
folder = root.external_mount_point
return folder
- security.declareProtected(Permissions.AccessContentsInformation,'getSubscriptionList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSubscriptionList')
def getSubscriptionList(self):
"""
Return a list of publications
@@ -345,7 +374,8 @@
return None
- security.declareProtected(Permissions.AccessContentsInformation,'getSynchronizationList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSynchronizationList')
def getSynchronizationList(self):
"""
Returns the list of subscriptions and publications
@@ -353,7 +383,8 @@
"""
return self.getSubscriptionList() + self.getPublicationList()
- security.declareProtected(Permissions.AccessContentsInformation,'getSubscriberList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSubscriberList')
def getSubscriberList(self):
"""
Returns the list of subscribers and subscriptions
@@ -364,13 +395,15 @@
s_list += publication.getSubscriberList()
return s_list
- security.declareProtected(Permissions.AccessContentsInformation,'getConflictList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getConflictList')
def getConflictList(self, context=None):
"""
Retrieve the list of all conflicts
Here the list is as follow :
[conflict_1,conflict2,...] where conflict_1 is like:
- ['publication',publication_id,object.getPath(),property_id,publisher_value,subscriber_value]
+ ['publication',publication_id,object.getPath(),property_id,
+ publisher_value,subscriber_value]
"""
path = self.resolveContext(context)
conflict_list = []
@@ -385,7 +418,8 @@
conflict_list += [conflict.__of__(subscriber)]
for subscription in self.getSubscriptionList():
sub_conflict_list = subscription.getConflictList()
- LOG('SynchronizationTool.getConflictList, sub_conflict_list',0,sub_conflict_list)
+ LOG('SynchronizationTool.getConflictList, sub_conflict_list',0,
+ sub_conflict_list)
for conflict in sub_conflict_list:
if isinstance(conflict,str):
import pdb; pdb.set_trace()
@@ -402,7 +436,8 @@
# return new_list
return conflict_list
- security.declareProtected(Permissions.AccessContentsInformation,'getDocumentConflictList')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getDocumentConflictList')
def getDocumentConflictList(self, context=None):
"""
Retrieve the list of all conflicts for a given document
@@ -411,7 +446,8 @@
return self.getConflictList(context)
- security.declareProtected(Permissions.AccessContentsInformation,'getSynchronizationState')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSynchronizationState')
def getSynchronizationState(self, context):
"""
context : the context on which we are looking for state
@@ -464,7 +500,8 @@
state_list += [[subscriber,state]]
return state_list
- security.declareProtected(Permissions.ModifyPortalContent, 'applyPublisherValue')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'applyPublisherValue')
def applyPublisherValue(self, conflict):
"""
after a conflict resolution, we have decided
@@ -494,7 +531,8 @@
directory._delObject(copy_id)
signature.setStatus(self.PUB_CONFLICT_MERGE)
- security.declareProtected(Permissions.ModifyPortalContent, 'applyPublisherDocument')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'applyPublisherDocument')
def applyPublisherDocument(self, conflict):
"""
apply the publisher value for all conflict of the given document
@@ -506,7 +544,8 @@
LOG('applyPublisherDocument, applying on conflict: ',0,conflict)
c.applyPublisherValue()
- security.declareProtected(Permissions.AccessContentsInformation, 'getPublisherDocumentPath')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getPublisherDocumentPath')
def getPublisherDocumentPath(self, conflict):
"""
apply the publisher value for all conflict of the given document
@@ -514,7 +553,8 @@
subscriber = conflict.getSubscriber()
return conflict.getObjectPath()
- security.declareProtected(Permissions.AccessContentsInformation, 'getPublisherDocument')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getPublisherDocument')
def getPublisherDocument(self, conflict):
"""
apply the publisher value for all conflict of the given document
@@ -548,8 +588,9 @@
directory._delObject(object_id)
# Import the conduit and get it
conduit_name = subscriber.getConduit()
- conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), [''])
- conduit = getattr(conduit_module, conduit_name)()
+ conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
+ globals(), locals(), [''])
+ conduit = getattr(conduit_module, conduit_name)()
conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id)
for c in self.getConflictList(conflict.getObjectPath()):
@@ -570,24 +611,33 @@
object_id = repotool._getId(docid, new_rev)
return object_id
- security.declareProtected(Permissions.AccessContentsInformation, 'getSubscriberDocumentPath')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSubscriberDocumentPath')
def getSubscriberDocumentPath(self, conflict):
"""
apply the publisher value for all conflict of the given document
"""
copy_path = conflict.getCopyPath()
if copy_path is not None:
- return copy_path
+ return copy_path
subscriber = conflict.getSubscriber()
publisher_object_path = conflict.getObjectPath()
publisher_object = self.unrestrictedTraverse(publisher_object_path)
- publisher_xml = self.getXMLObject(object=publisher_object,xml_mapping = subscriber.getXMLMapping())
+ publisher_xml = self.getXMLObject(object=publisher_object,
+ xml_mapping = subscriber.getXMLMapping())
directory = publisher_object.aq_inner.aq_parent
object_id = self._getCopyId(publisher_object)
# Import the conduit and get it
conduit_name = subscriber.getConduit()
- conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), [''])
- conduit = getattr(conduit_module, conduit_name)()
+ if conduit_name.startswith('Products'):
+ path = conduit_name
+ conduit_name = conduit_name.split('.')[-1]
+ conduit_module = __import__(path, globals(), locals(), [''])
+ conduit = getattr(conduit_module, conduit_name)()
+ else:
+ conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
+ globals(), locals(), [''])
+ conduit = getattr(conduit_module, conduit_name)()
conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id)
subscriber_document._conflict_resolution = 1
@@ -598,7 +648,8 @@
conflict.setCopyPath(copy_path)
return copy_path
- security.declareProtected(Permissions.AccessContentsInformation, 'getSubscriberDocument')
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getSubscriberDocument')
def getSubscriberDocument(self, conflict):
"""
apply the publisher value for all conflict of the given document
@@ -607,7 +658,8 @@
subscriber_object = self.unrestrictedTraverse(subscriber_object_path)
return subscriber_object
- security.declareProtected(Permissions.ModifyPortalContent, 'applySubscriberDocument')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'applySubscriberDocument')
def applySubscriberDocument(self, conflict):
"""
apply the subscriber value for all conflict of the given document
@@ -617,7 +669,8 @@
if c.getSubscriber() == subscriber:
c.applySubscriberValue()
- security.declareProtected(Permissions.ModifyPortalContent, 'applySubscriberValue')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'applySubscriberValue')
def applySubscriberValue(self, conflict,object=None):
"""
after a conflict resolution, we have decided
@@ -636,7 +689,8 @@
signature = subscriber.getSignature(object.getId()) # XXX may be change for rid
# Import the conduit and get it
conduit_name = subscriber.getConduit()
- conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), [''])
+ conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
+ globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
for xupdate in conflict.getXupdateList():
conduit.updateNode(xml=xupdate,object=object,force=1)
@@ -656,15 +710,18 @@
directory._delObject(copy_id)
signature.setStatus(self.PUB_CONFLICT_MERGE)
- security.declareProtected(Permissions.ModifyPortalContent, 'managePublisherValue')
- def managePublisherValue(self, subscription_url, property_id, object_path, RESPONSE=None):
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'managePublisherValue')
+ def managePublisherValue(self, subscription_url, property_id, object_path,
+ RESPONSE=None):
"""
Do whatever needed in order to store the local value on
the remote server
Suggestion (API)
add method to view document with applied xupdate
- of a given subscriber XX (ex. viewSubscriberDocument?path=ddd&subscriber_id=dddd)
+ of a given subscriber XX
+ (ex. viewSubscriberDocument?path=ddd&subscriber_id=dddd)
Version=Version CPS
"""
# Retrieve the conflict object
@@ -681,8 +738,10 @@
if RESPONSE is not None:
RESPONSE.redirect('manageConflicts')
- security.declareProtected(Permissions.ModifyPortalContent, 'manageSubscriberValue')
- def manageSubscriberValue(self, subscription_url, property_id, object_path, RESPONSE=None):
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manageSubscriberValue')
+ def manageSubscriberValue(self, subscription_url, property_id, object_path,
+ RESPONSE=None):
"""
Do whatever needed in order to store the remote value locally
and confirmed that the remote box should keep it's value
@@ -700,7 +759,8 @@
if RESPONSE is not None:
RESPONSE.redirect('manageConflicts')
- security.declareProtected(Permissions.ModifyPortalContent, 'manageSubscriberDocument')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'manageSubscriberDocument')
def manageSubscriberDocument(self, subscription_url, object_path):
"""
"""
@@ -711,7 +771,8 @@
break
self.managePublisherDocument(object_path)
- security.declareProtected(Permissions.ModifyPortalContent, 'managePublisherDocument')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'managePublisherDocument')
def managePublisherDocument(self, object_path):
"""
"""
@@ -742,7 +803,8 @@
return context.getPhysicalPath()
security.declarePublic('sendResponse')
- def sendResponse(self, to_url=None, from_url=None, sync_id=None,xml=None, domain=None, send=1):
+ def sendResponse(self, to_url=None, from_url=None, sync_id=None,xml=None,
+ domain=None, send=1):
"""
We will look at the url and we will see if we need to send mail, http
response, or just copy to a file.
@@ -760,7 +822,9 @@
decrypted.write(xml)
decrypted.close()
(status,output)=commands.getstatusoutput('gzip /tmp/%s' % filename)
- (status,output)=commands.getstatusoutput('gpg --yes --homedir /var/lib/zope/Products/ERP5SyncML/gnupg_keys -r "%s" -se /tmp/%s.gz' % (gpg_key,filename))
+ (status,output)=commands.getstatusoutput('gpg --yes --homedir \
+ /var/lib/zope/Products/ERP5SyncML/gnupg_keys -r "%s" -se \
+ /tmp/%s.gz' % (gpg_key,filename))
LOG('readResponse, gpg output:',0,output)
encrypted = file('/tmp/%s.gz.gpg' % filename,'r')
xml = encrypted.read()
@@ -775,7 +839,7 @@
return None
# we will send an http response
domain = aq_base(domain)
- LOG('sendResponse, will start sendHttpResponse, xml\n',0,xml)
+ LOG('sendResponse, will start sendHttpResponse, xml',0,'')
self.activate(activity='RAMQueue').sendHttpResponse(sync_id=sync_id,
to_url=to_url,
xml=xml, domain=domain)
@@ -814,7 +878,8 @@
pass_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib2.HTTPBasicAuthHandler(pass_mgr)
proxy_auth_handler = urllib2.ProxyBasicAuthHandler(pass_mgr)
- opener = urllib2.build_opener(proxy_handler, proxy_auth_handler,auth_handler,urllib2.HTTPHandler)
+ opener = urllib2.build_opener(proxy_handler, proxy_auth_handler,
+ auth_handler, urllib2.HTTPHandler)
urllib2.install_opener(opener)
to_encode = {'text':xml,'sync_id':sync_id}
encoded = urllib.urlencode(to_encode)
@@ -825,7 +890,8 @@
try:
result = urllib2.urlopen(request).read()
except socket.error, msg:
- self.activate(activity='RAMQueue').sendHttpResponse(to_url=to_url,sync_id=sync_id,xml=xml,domain=domain)
+ self.activate(activity='RAMQueue').sendHttpResponse(to_url=to_url,
+ sync_id=sync_id, xml=xml, domain=domain)
LOG('sendHttpResponse, socket ERROR:',0,msg)
return
@@ -853,7 +919,6 @@
# Login as a manager to make sure we can create objects
uf = self.acl_users
user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'')
- #user = uf.getUserById('syncml').__of__(uf)
newSecurityManager(None, user)
message_list = self.portal_activities.getMessageList()
LOG('sync, message_list:',0,message_list)
@@ -871,12 +936,12 @@
LOG('readResponse, ',0,'starting')
LOG('readResponse, self.getPhysicalPath: ',0,self.getPhysicalPath())
LOG('readResponse, sync_id: ',0,sync_id)
- #LOG('readResponse, text:',0,text)
# Login as a manager to make sure we can create objects
uf = self.acl_users
user = uf.getUserById('syncml').__of__(uf)
user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'')
newSecurityManager(None, user)
+ status_code = None
if text is not None:
# XXX We will look everywhere for a publication/subsription with
@@ -896,46 +961,38 @@
encrypted = file('/tmp/%s.gz.gpg' % filename,'w')
encrypted.write(text)
encrypted.close()
- (status,output)=commands.getstatusoutput('gpg --homedir /var/lib/zope/Products/ERP5SyncML/gnupg_keys -r "%s" --decrypt /tmp/%s.gz.gpg > /tmp/%s.gz' % (gpg_key,filename,filename))
- LOG('readResponse, gpg output:',0,output)
+ (status,output)=commands.getstatusoutput('gpg --homedir \
+ /var/lib/zope/Products/ERP5SyncML/gnupg_keys -r "%s" --decrypt \
+ /tmp/%s.gz.gpg > /tmp/%s.gz' % (gpg_key, filename, filename))
+ LOG('readResponse, gpg output:', 0, output)
(status,output)=commands.getstatusoutput('gunzip /tmp/%s.gz' % filename)
decrypted = file('/tmp/%s' % filename,'r')
text = decrypted.read()
- LOG('readResponse, text:',0,text)
+ LOG('readResponse, text:', 0, text)
decrypted.close()
commands.getstatusoutput('rm -f /tmp/%s' % filename)
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
# Get the target and then find the corresponding publication or
# Subscription
- LOG('readResponse, xml before parseSTring\n',0,text)
xml = parseString(text)
-
#XXX this function is not very optimized and should be improved
url = self.getTarget(xml)
-
for publication in self.getPublicationList():
- if publication.getPublicationUrl()==url and publication.getTitle()==sync_id:
+ if publication.getPublicationUrl()==url and \
+ publication.getTitle()==sync_id:
result = self.PubSync(sync_id,xml)
# Then encrypt the message
xml = result['xml']
-
#must be commented because this method is alredy called
#xml = self.sendResponse(xml=xml,domain=publication,send=0)
return xml
+
for subscription in self.getSubscriptionList():
if subscription.getSubscriptionUrl()==url and \
subscription.getTitle()==sync_id:
- next_status = self.getNextSyncBodyStatus(xml, None)
- if next_status is not None:
- status_code = self.getStatusCode(next_status)
- LOG('readResponse status code :',0,status_code)
- if status_code == self.UNAUTHORIZED or \
- status_code == self.AUTH_REQUIRED:
- LOG('readResponse', 0, 'Authentication required')
- raise ValueError, "Authentication required"
- else:
- result = self.activate(activity='RAMQueue').SubSync(sync_id,xml)
- #result = self.SubSync(sync_id,xml)
+ result = self.activate(activity='RAMQueue').SubSync(sync_id,
+ text)
+ #result = self.SubSync(sync_id,xml)
# we use from only if we have a file
elif isinstance(from_url, str):
@@ -953,14 +1010,16 @@
xml = None
return xml
- security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'getPublicationIdFromTitle')
def getPublicationIdFromTitle(self, title):
"""
simply return an id from a title
"""
return 'pub_' + title
- security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle')
+ security.declareProtected(Permissions.ModifyPortalContent,
+ 'getPublicationIdFromTitle')
def getSubscriptionIdFromTitle(self, title):
"""
simply return an id from a title
@@ -973,7 +1032,8 @@
"""
# Import the conduit and get it
from Products.ERP5SyncML import Conduit
- conduit_module = __import__('.'.join([Conduit.__name__, conduit]), globals(), locals(), [''])
+ conduit_module = __import__('.'.join([Conduit.__name__, conduit]),
+ globals(), locals(), [''])
conduit_object = getattr(conduit_module, conduit)()
return conduit_object.addNode(**kw)
Modified: erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py (original)
+++ erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py Thu May 10 14:13:52 2007
@@ -47,7 +47,8 @@
class XMLSyncUtilsMixin(SyncCode):
def SyncMLHeader(self, session_id, msg_id, target, source, target_name=None,
- source_name=None):
+ source_name=None, dataCred=None, authentication_format='b64',
+ authentication_type='syncml:auth-basic'):
"""
Since the Header is always almost the same, this is the
way to set one quickly.
@@ -61,14 +62,22 @@
xml(' <MsgID>%s</MsgID>\n' % msg_id)
xml(' <Target>\n')
xml(' <LocURI>%s</LocURI>\n' % target)
- if target_name is not None:
+ if target_name not in (None, ''):
xml(' <LocName>%s</LocName>\n' %target_name)
xml(' </Target>\n')
xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % source)
- if source_name is not None:
+ if source_name not in (None, ''):
xml(' <LocName>%s</LocName>\n' % source_name)
xml(' </Source>\n')
+ if dataCred not in (None, ''):
+ xml(' <Cred>\n')
+ xml(' <Meta>\n')
+ xml(' <Format>%s</Format>\n' % authentication_format)
+ xml(' <Type>%s</Type>\n' % authentication_type)
+ xml(' </Meta>\n')
+ xml(' <Data>%s</Data>\n' % dataCred)
+ xml(' </Cred>\n')
xml(' </SyncHdr>\n')
xml_a = ''.join(xml_list)
return xml_a
@@ -103,7 +112,7 @@
return xml_a
def SyncMLStatus(self, cmd_id, target_ref, source_ref, sync_code,
- next_anchor):
+ next_anchor=None):
"""
Since the Status section is always almost the same, this is the
way to set one quickly.
@@ -115,13 +124,14 @@
xml(' <TargetRef>%s</TargetRef>\n' % target_ref)
xml(' <SourceRef>%s</SourceRef>\n' % source_ref)
xml(' <Data>%s</Data>\n' % sync_code)
- xml(' <Item>\n')
- xml(' <Data>\n')
- xml(' <Anchor xmlns=\'syncml:metinf\'>\n')
- xml(' <Next>%s</Next>\n' % next_anchor)
- xml(' </Anchor>\n')
- xml(' </Data>\n')
- xml(' </Item>\n')
+ if next_anchor is not None:
+ xml(' <Item>\n')
+ xml(' <Data>\n')
+ xml(' <Anchor xmlns=\'syncml:metinf\'>\n')
+ xml(' <Next>%s</Next>\n' % next_anchor)
+ xml(' </Anchor>\n')
+ xml(' </Data>\n')
+ xml(' </Item>\n')
xml(' </Status>\n')
xml_a = ''.join(xml_list)
return xml_a
@@ -416,27 +426,6 @@
return int(subnode.childNodes[0].data)
return None
-
- #def getStatusCode(self, xml):
- # """
- # Return the value of the alert code inside the xml_stream
- # """
- # # Get informations from the body
- # first_node = xml.childNodes[0]
- # if first_node.nodeName != "SyncML":
- # print "This is not a SyncML message"
- #
- # client_body = first_node.childNodes[3]
- # if client_body.nodeName != "SyncBody":
- # print "This is not a SyncML Body"
- #
- # for subnode in client_body.childNodes:
- # if subnode.nodeName=='Status':
- # for subnode2 in subnode.childNodes:
- # if subnode2.nodeType == subnode.ELEMENT_NODE and subnode2.nodeName == 'Data':
- # return int(subnode2.childNodes[0].data)
- # return None
-
def getStatusCommand(self, xml):
"""
Return the value of the command inside the xml_stream
@@ -447,6 +436,44 @@
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Cmd':
return subnode.childNodes[0].data
return None
+
+ def getCred(self, xml):
+ """
+ return the credential information : type, format and data
+ """
+ format=''
+ type=''
+ data=''
+
+
+ first_node = xml.childNodes[0]
+ if first_node.nodeName != "SyncML":
+ print "This is not a SyncML message"
+ # Get informations from the header
+ xml_header = first_node.childNodes[1]
+ if xml_header.nodeName != "SyncHdr":
+ LOG('PubSyncModif',0,'This is not a SyncML Header')
+ raise ValueError, "Sorry, This is not a SyncML Header"
+
+ for subnode in xml_header.childNodes:
+ if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='Cred':
+ for subnode2 in subnode.childNodes:
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and \
+ subnode2.nodeName == 'Meta':
+ for subnode3 in subnode2.childNodes:
+ if subnode3.nodeType == subnode3.ELEMENT_NODE and \
+ subnode3.nodeName == 'Format':
+ if len(subnode3.childNodes) > 0:
+ format=subnode3.childNodes[0].data
+ if subnode3.nodeType == subnode3.ELEMENT_NODE and \
+ subnode3.nodeName == 'Type':
+ if len(subnode3.childNodes) > 0:
+ type=subnode3.childNodes[0].data
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and \
+ subnode2.nodeName == 'Data':
+ if len(subnode2.childNodes) > 0:
+ data=subnode2.childNodes[0].data
+ return (format, type, data)
def getAlertCode(self, xml_stream):
"""
@@ -739,13 +766,13 @@
# object_gid = gid_generator()
force = 0
if syncml_data.count('\n') < self.MAX_LINES and not object.id.startswith('.'): # If not we have to cut
- LOG('getSyncMLData',0,'xml_mapping: %s' % str(domain.xml_mapping))
- LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml)))
- LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list))
- LOG('getSyncMLData',0,'hasSignature: %s' % str(subscriber.hasSignature(object_gid)))
- LOG('getSyncMLData',0,'alert_code == slowsync: %s' % str(self.getAlertCode(remote_xml)==self.SLOW_SYNC))
+ #LOG('getSyncMLData',0,'xml_mapping: %s' % str(domain.xml_mapping))
+ #LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml)))
+ #LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list))
+ #LOG('getSyncMLData',0,'hasSignature: %s' % str(subscriber.hasSignature(object_gid)))
+ #LOG('getSyncMLData',0,'alert_code == slowsync: %s' % str(self.getAlertCode(remote_xml)==self.SLOW_SYNC))
signature = subscriber.getSignature(object_gid)
- LOG('getSyncMLData',0,'current object: %s' % str(object.getId()))
+ #LOG('getSyncMLData',0,'current object: %s' % str(object.getId()))
# Here we first check if the object was modified or not by looking at dates
if signature is not None:
signature.checkSynchronizationNeeded(object)
@@ -774,7 +801,7 @@
rest_string = xml_string[len(short_string):]
#LOG('XMLSyncUtils',0,'rest_string: %s' % str(rest_string))
i += 1
- LOG('getSyncMLData',0,'setPartialXML with: %s' % str(rest_string))
+ #LOG('getSyncMLData',0,'setPartialXML with: %s' % str(rest_string))
signature.setPartialXML(rest_string)
status =self.PARTIAL
signature.setAction('Add')
@@ -787,8 +814,8 @@
elif signature.getStatus()==self.NOT_SYNCHRONIZED \
or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping)
- LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object)))
- LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus()))
+ #LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object)))
+ #LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus()==self.PUB_CONFLICT_MERGE:
xml_confirmation += self.SyncMLConfirmation(cmd_id,object.id,
self.CONFLICT_MERGE,'Replace')
@@ -821,7 +848,7 @@
signature.setTempXML(xml_object)
# Now we can apply the xupdate from the subscriber
subscriber_xupdate = signature.getSubscriberXupdate()
- LOG('getSyncMLData subscriber_xupdate',0,subscriber_xupdate)
+ #LOG('getSyncMLData subscriber_xupdate',0,subscriber_xupdate)
if subscriber_xupdate is not None:
old_xml = signature.getXML()
conduit.updateNode(xml=subscriber_xupdate, object=object,
@@ -1080,7 +1107,6 @@
if xml_header.nodeName != "SyncHdr":
LOG('PubSyncModif',0,'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header"
- return
subscriber = domain # If we are the client, this is fine
simulate = 0 # used by applyActionList, should be 0 for client
@@ -1103,11 +1129,12 @@
if last_xml != '':
has_response = 1
if domain.domain_type == self.PUB: # We always reply
- self.sendResponse(from_url=domain.publication_url, to_url=subscriber.subscription_url,
- sync_id=domain.getTitle(), xml=last_xml,domain=domain)
+ self.sendResponse(from_url=domain.publication_url,
+ to_url=subscriber.subscription_url, sync_id=domain.getTitle(),
+ xml=last_xml,domain=domain)
elif domain.domain_type == self.SUB:
- self.sendResponse(from_url=domain.subscription_url, to_url=domain.publication_url,
- sync_id=domain.getTitle(), xml=last_xml,domain=domain)
+ self.sendResponse(from_url=domain.subscription_url,
+ to_url=domain.publication_url, sync_id=domain.getTitle(), xml=last_xml,domain=domain)
return {'has_response':has_response,'xml':last_xml}
subscriber.setLastSentMessage('')
@@ -1135,7 +1162,7 @@
subscriber=subscriber,
remote_xml=remote_xml,
conduit=conduit, simulate=simulate)
- LOG('SyncModif, has_next_action:',0,has_next_action)
+ #LOG('SyncModif, has_next_action:',0,has_next_action)
xml_list = []
xml = xml_list.append
Modified: erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml Thu May 10 14:13:52 2007
@@ -127,6 +127,36 @@
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td>
</tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Authentication Required
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="checkbox" name="auth_required" value="1" <dtml-if expr="isAuthenticationRequired()">CHECKED</dtml-if>>
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Format authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_format" value="<dtml-var getAuthenticationFormat>" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Type authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_type" value="<dtml-var getAuthenticationType>" size="40" />
+ </td>
+ </tr>
</table>
<table>
<tr>
Modified: erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml Thu May 10 14:13:52 2007
@@ -137,6 +137,46 @@
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td>
</tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Login
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="login" value="<dtml-var getLogin>" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Password
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="password" name="password" value="<dtml-var getPassword>" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Format authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_format" value="<dtml-var getAuthenticationFormat>" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Type authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_type" value="<dtml-var getAuthenticationType>" size="40" />
+ </td>
+ </tr>
</table>
<table>
<tr>
Modified: erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml Thu May 10 14:13:52 2007
@@ -125,6 +125,36 @@
</tr>
<tr>
<td align="left" valign="top">
+ <div class="form-label">
+ Authentication Required
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="checkbox" name="auth_required" value="1">
+ </td>
+ </tr>
+ <tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Format authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_format" size="40" />
+ </td>
+ </tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Type authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_type" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
Modified: erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml Thu May 10 14:13:52 2007
@@ -135,6 +135,45 @@
</tr>
<tr>
<td align="left" valign="top">
+ <div class="form-label">
+ Login
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="login" size="40" /> </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Password
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="password" name="password" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Format authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_format" size="40" />
+ </td>
+ </tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Type authentication
+ </label></div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="authentication_type" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <tr>
+ <td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
Modified: erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py?rev=14439&r1=14438&r2=14439&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py (original)
+++ erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py Thu May 10 14:13:52 2007
@@ -42,6 +42,10 @@
from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG
+try:
+ from base64 import b64encode, b64decode
+except ImportError:
+ from base64 import encodestring as b64encode, decodestring as b64decode
class TestERP5SyncML(ERP5TypeTestCase):
# Different variables used for this test
@@ -51,7 +55,7 @@
last_name1 = 'Robin'
# At the beginning, I was using iso-8859-15 strings, but actually
# erp5 is using utf-8 everywhere
- #description1 = 'description1 --- $sdfrç_sdfsçdf_oisfsopf'
+ #description1 = 'description1 --- $sdfrç_sdfsçdf_oisfsopf'
description1 = 'description1 --- $sdfr\xc3\xa7_sdfs\xc3\xa7df_oisfsopf'
lang1 = 'fr'
format2 = 'html'
@@ -59,12 +63,12 @@
format4 = 'txt'
first_name2 = 'Jean-Paul'
last_name2 = 'Smets'
- #description2 = 'description2éà@ $*< <<< ----- >>>></title>&oekd'
+ #description2 = 'description2éà @ $*< <<< ----- >>>></title>&oekd'
description2 = 'description2\xc3\xa9\xc3\xa0@ $*< <<< ----- >>>></title>&oekd'
lang2 = 'en'
first_name3 = 'Yoshinori'
last_name3 = 'Okuji'
- #description3 = 'description3 çsdf__sdfççç_df___&&é]]]°°°°°°'
+ #description3 = 'description3 çsdf__sdfççç_df___&&é]]]°°°°°°'
description3 = 'description3 \xc3\xa7sdf__sdf\xc3\xa7\xc3\xa7\xc3\xa7_df___&&\xc3\xa9]]]\xc2\xb0\xc2\xb0\xc2\xb0\xc2\xb0\xc2\xb0\xc2\xb0'
#description4 = 'description4 sdflkmooo^^^^]]]]]{{{{{{{'
description4 = 'description4 sdflkmooo^^^^]]]]]{{{{{{{'
@@ -182,10 +186,10 @@
def login(self, quiet=0):
uf = self.getPortal().acl_users
- uf._doAddUser('seb', '', ['Manager'], [])
+ uf._doAddUser('fab', 'myPassword', ['Manager'], [])
uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], [])
uf._doAddUser('syncml', '', ['Manager'], [])
- user = uf.getUserById('seb').__of__(uf)
+ user = uf.getUserById('fab').__of__(uf)
newSecurityManager(None, user)
def populatePersonServer(self, quiet=0, run=run_all_test):
@@ -317,7 +321,6 @@
to define it here because it is specific to the unit testing
"""
portal_sync = self.getSynchronizationTool()
- #portal_sync.email = None # XXX To be removed
subscription = portal_sync.getSubscription(id)
publication = None
for publication in portal_sync.getPublicationList():
@@ -984,7 +987,7 @@
self.failUnless(person_s.getDescription()==self.description3)
self.failUnless(person_c1.getDescription()==self.description3)
- def test_25_MultiNodeConflict(self, quiet=0, run=run_all_test):
+ def test_25_MultiNodeConflict(self, quiet=0, run=1):
"""
We will create conflicts with 3 differents nodes, and we will
solve it by taking one full version of documents.
@@ -1097,9 +1100,9 @@
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
person2_c = person_client1._getOb(self.id2)
- person1_s.manage_setLocalRoles('seb',['Manager','Owner'])
+ person1_s.manage_setLocalRoles('fab',['Manager','Owner'])
person2_s.manage_setLocalRoles('jp',['Manager','Owner'])
- person2_s.manage_delLocalRoles(['seb'])
+ person2_s.manage_delLocalRoles(['fab'])
self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2)
role_1_s = person1_s.get_local_roles()
@@ -1182,7 +1185,7 @@
def test_30_GetSynchronizationType(self, quiet=0, run=run_all_test):
# We will try to update some simple data, first
- # we change on the server side, the on the client side
+ # we change on the server side, then on the client side
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Get Synchronization Type ')
@@ -1257,20 +1260,20 @@
self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_c)
- def test_32_AddOneWaySubscription(self, quiet=0, run=1):
+ def test_32_AddOneWaySubscription(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Add One Way Subscription ')
LOG('Testing... ',0,'test_32_AddOneWaySubscription')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
- portal_sync.manage_addSubscription(self.sub_id1,self.publication_url,
- self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
- '','ERP5Conduit','')
+ portal_sync.manage_addSubscription(self.sub_id1, self.publication_url,
+ self.subscription_url1, '/%s/person_client1' % portal_id,
+ 'objectValues', '', 'ERP5Conduit', '')
sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None)
- def test_33_OneWaySync(self, quiet=0, run=1):
+ def test_33_OneWaySync(self, quiet=0, run=run_all_test):
"""
We will test if we can synchronize only from to server to the client.
We want to make sure in this case that all modifications on the client
@@ -1314,6 +1317,234 @@
self.assertEquals(person1_s.getFirstName(),self.first_name1)
+ def test_34_encoding(self, quiet=0, run=run_all_test):
+ """
+ We will test if we can encode strings with b64encode to encode
+ the login and password for authenticated sessions
+ """
+ #when there will be other format implemented with encode method,
+ #there will be tested here
+
+ if not run: return
+ self.test_08_FirstSynchronization(quiet=1,run=1)
+ if not quiet:
+ ZopeTestCase._print('\nTest Strings Encoding ')
+ LOG('Testing... ',0,'test_34_encoding')
+
+ #define some strings :
+ python = 'www.python.org'
+ awaited_result_python = "d3d3LnB5dGhvbi5vcmc="
+ long_string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO\
+PQRSTUVWXYZéèçà @^~µ&²0123456789!@#0^&*();:<>,. []{}\xc3\xa7sdf__\
+sdf\xc3\xa7\xc3\xa7\xc3\xa7_df___&&\xc3\xa9]]]\xc2\xb0\xc2\xb0\xc2\
+\xb0\xc2\xb0\xc2\xb0\xc2\xb0"
+#= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZéèçà @^~µ&²012345
+#6789!@#0^&*();:<>,. []{}çsdf__sdfççç_df___&&é]]]°°°°°°'"
+
+ awaited_result_long_string = 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH\
+SElKS0xNTk9QUVJTVFVWV1hZWsOpw6jDp8OgQF5+wrUmwrIwMTIzNDU2Nzg5IUAjMF4mKigpOzo8Pi\
+wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
+
+ #test just b64encode
+ self.assertEqual(b64encode(python), awaited_result_python)
+ self.assertEqual(b64encode(""), "")
+ self.assertEqual(b64encode(long_string), awaited_result_long_string)
+
+ self.assertEqual(b64decode(awaited_result_python), python)
+ self.assertEqual(b64decode(""), "")
+ self.assertEqual(b64decode(awaited_result_long_string), long_string)
+
+ # test with the ERP5 functions
+ portal_sync = self.getSynchronizationTool()
+ publication = portal_sync.getPublication(self.pub_id)
+ subscription1 = portal_sync.getSubscription(self.sub_id1)
+
+ string_encoded = subscription1.encode('b64', python)
+ self.assertEqual(string_encoded, awaited_result_python)
+ string_decoded = subscription1.decode('b64', awaited_result_python)
+ self.assertEqual(string_decoded, python)
+ self.failUnless(subscription1.isDecodeEncodeTheSame(string_encoded,
+ python, 'b64'))
+ self.failUnless(subscription1.isDecodeEncodeTheSame(string_encoded,
+ string_decoded, 'b64'))
+
+ string_encoded = subscription1.encode('b64', long_string)
+ self.assertEqual(string_encoded, awaited_result_long_string)
+ string_decoded = subscription1.decode('b64', awaited_result_long_string)
+ self.assertEqual(string_decoded, long_string)
+ self.failUnless(subscription1.isDecodeEncodeTheSame(string_encoded,
+ long_string, 'b64'))
+ self.failUnless(subscription1.isDecodeEncodeTheSame(string_encoded,
+ string_decoded, 'b64'))
+
+ self.assertEqual(subscription1.encode('b64', ''), '')
+ self.assertEqual(subscription1.decode('b64', ''), '')
+ self.failUnless(subscription1.isDecodeEncodeTheSame(
+ subscription1.encode('b64', ''), '', 'b64'))
+
+ def addAuthenticationToPublication(self, publication_id, login, password,
+ auth_format, auth_type):
+ """
+ add authentication to the publication
+ """
+ portal_sync = self.getSynchronizationTool()
+ pub = portal_sync.getPublication(publication_id)
+ pub.setAuthentication(True)
+ pub.setLogin(login)
+ pub.setPassword(password)
+ pub.setAuthenticationFormat(auth_format)
+ pub.setAuthenticationType(auth_type)
+
+
+ def addAuthenticationToSubscription(self, subscription_id, login, password,
+ auth_format, auth_type):
+ """
+ add authentication to the subscription
+ """
+ portal_sync = self.getSynchronizationTool()
+ sub = portal_sync.getSubscription(subscription_id)
+ sub.setAuthentication(True)
+ sub.setAuthenticated(False)
+ sub.setLogin(login)
+ sub.setPassword(password)
+ sub.setAuthenticationFormat(auth_format)
+ sub.setAuthenticationType(auth_type)
+
+ def verifyFirstNameAndLastNameAreSynchronized(self, first_name,
+ last_name, person_server, person_client):
+ """
+ verify if the first and last name are synchronized
+ """
+ self.failUnless(person_server.getFirstName()==first_name)
+ self.failUnless(person_server.getLastName()==last_name)
+ self.failUnless(person_client.getFirstName()==first_name)
+ self.failUnless(person_client.getLastName()==last_name)
+
+ def verifyFirstNameAndLastNameAreNotSynchronized(self, first_name,
+ last_name, person_server, person_client):
+ """
+ verify that the first and last name are NOT synchronized
+ """
+ self.failUnless(person_server.getFirstName()!=first_name)
+ self.failUnless(person_server.getLastName()!=last_name)
+ self.failUnless(person_client.getFirstName()==first_name)
+ self.failUnless(person_client.getLastName()==last_name)
+
+ def test_35_authentication(self, quiet=0, run=1):
+ """
+ we will test
+ - if we can't synchronize without good authentication for an
+ autentication required publication.
+ - if we can synchronize without of with (and bad or good) authentication
+ for an not required autentication publication
+ """
+
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Authentication ')
+ LOG('Testing... ',0,'test_35_authentication')
+
+ self.test_08_FirstSynchronization(quiet=1,run=1)
+ # First we do only modification on client
+ portal_sync = self.getSynchronizationTool()
+ person_server = self.getPersonServer()
+ person1_s = person_server._getOb(self.id1)
+ person_client1 = self.getPersonClient1()
+ person1_c = person_client1._getOb(self.id1)
+
+ kw = {'first_name':self.first_name3,'last_name':self.last_name3}
+ person1_c.edit(**kw)
+
+ #check that it's not synchronize
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name3,
+ self.last_name3, person1_s, person1_c)
+ self.synchronize(self.sub_id1)
+ #now it should be synchronize
+ self.checkSynchronizationStateIsSynchronized()
+ self.verifyFirstNameAndLastNameAreSynchronized(self.first_name3,
+ self.last_name3, person1_s, person1_c)
+
+
+ #adding authentication :
+ self.addAuthenticationToPublication(self.pub_id, 'fab', 'myPassword', 'b64',
+ 'syncml:auth-basic')
+ # try to synchronize without authentication on the subscription, it
+ # should failed
+ kw = {'first_name':self.first_name2,'last_name':self.last_name2}
+ person1_c.edit(**kw)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name2,
+ self.last_name2, person1_s, person1_c)
+ # here, before and after synchronization, the person1_s shoudn't have
+ # the name as the person1_c because the user isn't authenticated
+ self.synchronize(self.sub_id1)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name2,
+ self.last_name2, person1_s, person1_c)
+
+ #try to synchronize whith an authentication on both the client and server
+ self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'myPassword',
+ 'b64', 'syncml:auth-basic')
+ #now it should be correctly synchronize
+ self.synchronize(self.sub_id1)
+ self.checkSynchronizationStateIsSynchronized()
+ self.verifyFirstNameAndLastNameAreSynchronized(self.first_name2,
+ self.last_name2, person1_s, person1_c)
+
+ #try to synchronize with a bad login and/or password
+ #test if login is case sensitive (it should be !)
+ self.addAuthenticationToSubscription(self.sub_id1, 'fAb', 'myPassword',
+ 'b64', 'syncml:auth-basic')
+ kw = {'first_name':self.first_name1,'last_name':self.last_name1}
+ person1_c.edit(**kw)
+ self.synchronize(self.sub_id1)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name1,
+ self.last_name1, person1_s, person1_c)
+
+ #with a paswword case sensitive
+ self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'mypassword',
+ 'b64', 'syncml:auth-basic')
+ kw = {'first_name':self.first_name1,'last_name':self.last_name1}
+ person1_c.edit(**kw)
+ self.synchronize(self.sub_id1)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name1,
+ self.last_name1, person1_s, person1_c)
+
+
+ #with the good password
+ self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'myPassword',
+ 'b64', 'syncml:auth-basic')
+ #now it should be correctly synchronize
+ self.synchronize(self.sub_id1)
+ self.checkSynchronizationStateIsSynchronized()
+ self.verifyFirstNameAndLastNameAreSynchronized(self.first_name1,
+ self.last_name1, person1_s, person1_c)
+
+ #verify that the login and password with utf8 caracters are accecpted
+
+ # add a user with an utf8 login
+ uf = self.getPortal().acl_users
+ uf._doAddUser('\xc3\xa9pouet', 'ploum', ['Manager'], []) # \xc3\xa9pouet = épouet
+ user = uf.getUserById('\xc3\xa9pouet').__of__(uf)
+ newSecurityManager(None, user)
+
+ self.addAuthenticationToPublication(self.pub_id, '\xc3\xa9pouet', 'ploum',
+ 'b64', 'syncml:auth-basic')
+ #first, try with a wrong login :
+ self.addAuthenticationToSubscription(self.sub_id1, 'pouet', 'ploum',
+ 'b64', 'syncml:auth-basic')
+ kw = {'first_name':self.first_name3,'last_name':self.last_name3}
+ person1_c.edit(**kw)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name3,
+ self.last_name3, person1_s, person1_c)
+ self.synchronize(self.sub_id1)
+ self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name3,
+ self.last_name3, person1_s, person1_c)
+ #now with the good :
+ self.addAuthenticationToSubscription(self.sub_id1, '\xc3\xa9pouet', 'ploum',
+ 'b64', 'syncml:auth-basic')
+ self.synchronize(self.sub_id1)
+ self.verifyFirstNameAndLastNameAreSynchronized(self.first_name3,
+ self.last_name3, person1_s, person1_c)
+ self.checkSynchronizationStateIsSynchronized()
if __name__ == '__main__':
framework()
More information about the Erp5-report
mailing list