Commit c69b4e86 authored by Sebastien Robin's avatar Sebastien Robin

fabien finished to implement authentication, and he added tests for it

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14439 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 999e908f
...@@ -129,11 +129,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -129,11 +129,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
LOG('addNode',0,'xml_reconstitued: %s' % str(xml)) LOG('addNode',0,'xml_reconstitued: %s' % str(xml))
# In the case where this new node is a object to add # 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 xml.nodeName in self.XUPDATE_INSERT_OR_ADD and self.getSubObjectDepth(xml)==0:
if self.isHistoryAdd(xml)!=-1: # bad hack XXX to be removed if self.isHistoryAdd(xml)!=-1: # bad hack XXX to be removed
for element in self.getXupdateElementList(xml): for element in self.getXupdateElementList(xml):
...@@ -216,7 +211,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -216,7 +211,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
object_id = self.getAttribute(xml,'id') object_id = self.getAttribute(xml,'id')
elif self.getSubObjectDepth(xml)==1: elif self.getSubObjectDepth(xml)==1:
object_id = self.getSubObjectId(xml) object_id = self.getSubObjectId(xml)
#LOG('ERP5Conduit',0,'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml))
elif self.getSubObjectDepth(xml)==2: elif self.getSubObjectDepth(xml)==2:
# we have to call delete node on a subsubobject # we have to call delete node on a subsubobject
sub_object_id = self.getSubObjectId(xml) sub_object_id = self.getSubObjectId(xml)
...@@ -706,14 +700,11 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -706,14 +700,11 @@ class ERP5Conduit(XMLSyncUtilsMixin):
for subnode in self.getElementNodeList(xml): for subnode in self.getElementNodeList(xml):
if not(subnode.nodeName in self.NOT_EDITABLE_PROPERTY): if not(subnode.nodeName in self.NOT_EDITABLE_PROPERTY):
keyword_type = self.getPropertyType(subnode) keyword_type = self.getPropertyType(subnode)
LOG('newObject',0,str(subnode.childNodes))
# This is the case where the property is a list # This is the case where the property is a list
keyword=str(subnode.nodeName) keyword=str(subnode.nodeName)
if len(subnode.childNodes) > 0: # We check that this tag is not empty if len(subnode.childNodes) > 0: # We check that this tag is not empty
data = subnode.childNodes[0].data data = subnode.childNodes[0].data
args[keyword]=data args[keyword]=data
LOG('newObject',0,'keyword: %s' % str(keyword))
LOG('newObject',0,'keywordtype: %s' % str(keyword_type))
#if args.has_key(keyword): #if args.has_key(keyword):
# LOG('newObject',0,'data: %s' % str(args[keyword])) # LOG('newObject',0,'data: %s' % str(args[keyword]))
if args.has_key(keyword): if args.has_key(keyword):
...@@ -722,8 +713,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -722,8 +713,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
self.addNode(object=object,xml=subnode, force=1) self.addNode(object=object,xml=subnode, force=1)
# We should first edit the object # We should first edit the object
args = self.getFormatedArgs(args=args) 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, # edit the object with a dictionnary of arguments,
# like {"telephone_number":"02-5648"} # like {"telephone_number":"02-5648"}
#object._edit(**args) #object._edit(**args)
...@@ -885,7 +874,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -885,7 +874,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
dict_list = map(lambda x:x.split(':'),data[1:-1].split(',')) dict_list = map(lambda x:x.split(':'),data[1:-1].split(','))
data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list) data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list)
data = dict(data) data = dict(data)
LOG('convertXmlValue',0,'data: %s' % str(data))
return data return data
# XXX is it the right place ? It should be in XupdateUtils, but here we # XXX is it the right place ? It should be in XupdateUtils, but here we
...@@ -997,7 +985,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -997,7 +985,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
add_action = self.isWorkflowActionAddable(object=object, add_action = self.isWorkflowActionAddable(object=object,
status=status,wf_tool=wf_tool, status=status,wf_tool=wf_tool,
wf_id=wf_id,xml=xml) 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) LOG('addNode, workflow_history add_action:',0,add_action)
if add_action and not simulate: if add_action and not simulate:
LOG('addNode, setting status:',0,'ok') LOG('addNode, setting status:',0,'ok')
......
...@@ -152,7 +152,9 @@ class Publication(Subscription): ...@@ -152,7 +152,9 @@ class Publication(Subscription):
constructors = (addPublication,) constructors = (addPublication,)
# Constructor # 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 constructor
""" """
...@@ -169,6 +171,9 @@ class Publication(Subscription): ...@@ -169,6 +171,9 @@ class Publication(Subscription):
self.setConduit(conduit) self.setConduit(conduit)
Folder.__init__(self, id) Folder.__init__(self, id)
self.title = title self.title = title
self.auth_required = auth_required
self.authentication_format = authentication_format
self.authentication_type = authentication_type
def getPublicationUrl(self): def getPublicationUrl(self):
""" """
...@@ -189,6 +194,42 @@ class Publication(Subscription): ...@@ -189,6 +194,42 @@ class Publication(Subscription):
""" """
self.publication_url = 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): def addSubscriber(self, subscriber):
""" """
Add a new subscriber to the publication Add a new subscriber to the publication
......
...@@ -34,6 +34,10 @@ from xml.dom.minidom import parse, parseString ...@@ -34,6 +34,10 @@ from xml.dom.minidom import parse, parseString
from XMLSyncUtils import XMLSyncUtils from XMLSyncUtils import XMLSyncUtils
from Conduit.ERP5Conduit import ERP5Conduit from Conduit.ERP5Conduit import ERP5Conduit
from Products.CMFCore.utils import getToolByName 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 import commands
from zLOG import LOG from zLOG import LOG
...@@ -43,17 +47,19 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -43,17 +47,19 @@ class PublicationSynchronization(XMLSyncUtils):
""" """
def PubSyncInit(self, publication=None, xml_client=None, subscriber=None, def PubSyncInit(self, publication=None, xml_client=None, subscriber=None,
sync_type=None, auth_required=0): sync_type=None):
""" """
Read the client xml message Read the client xml message
Send the first XML message from the server Send the first XML message from the server
""" """
LOG('PubSyncInit',0,'Starting... publication: %s' % str(publication)) LOG('PubSyncInit',0,'Starting... publication: %s' % str(publication))
#the session id is set at the same value of those of the client #the session id is set at the same value of those of the client
subscriber.setSessionId(self.getSessionId(xml_client)) subscriber.setSessionId(self.getSessionId(xml_client))
# for a new session, the message Id must be reset #same for the message id
subscriber.resetMessageId() 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 #the last_message_id is 1 because the message that
#we are about to send is the message 1 #we are about to send is the message 1
subscriber.initLastMessageId(1) subscriber.initLastMessageId(1)
...@@ -67,33 +73,83 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -67,33 +73,83 @@ class PublicationSynchronization(XMLSyncUtils):
alert_code = self.getAlertCode(xml_client) alert_code = self.getAlertCode(xml_client)
cred = self.checkCred(xml_client) cred = self.checkCred(xml_client)
#XXX this is in developement, it's just for tests #XXX this is in developement, it's just for tests
if not cred and auth_required: if publication.isAuthenticationRequired():
LOG('PubSyncInit',0,'authentication required') if not cred:
# Prepare the xml message for the Sync initialization package LOG('PubSyncInit',0,'authentication required')
cmd_id = 1 # specifies a SyncML message-unique command identifier # Prepare the xml message for the Sync initialization package
xml_list = [] cmd_id = 1 # specifies a SyncML message-unique command identifier
xml = xml_list.append xml_list = []
xml('<SyncML>\n') xml = xml_list.append
# syncml header xml('<SyncML>\n')
xml(self.SyncMLHeader(subscriber.getSessionId(), # syncml header
subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(), xml(self.SyncMLHeader(subscriber.getSessionId(),
publication.getPublicationUrl())) subscriber.getMessageId(), subscriber.getSubscriptionUrl(),
# syncml body publication.getPublicationUrl()))
xml(' <SyncBody>\n') # syncml body
# chal message xml(' <SyncBody>\n')
xml(self.SyncMLChal(cmd_id, "SyncHdr", publication.getPublicationUrl(), # chal message
subscriber.getSubscriptionUrl(), "b64", "syncml:auth-basic", xml(self.SyncMLChal(cmd_id, "SyncHdr",
self.UNAUTHORIZED)) publication.getPublicationUrl(), subscriber.getSubscriptionUrl(),
cmd_id += 1 publication.getAuthenticationFormat(),
publication.getAuthenticationType(), self.AUTH_REQUIRED))
xml(' </SyncBody>\n') cmd_id += 1
xml('</SyncML>\n') xml(' </SyncBody>\n')
xml_a = ''.join(xml_list)
xml('</SyncML>\n')
self.sendResponse(from_url=publication.getPublicationUrl(), xml_a = ''.join(xml_list)
to_url=subscriber.getSubscriptionUrl(),sync_id=publication.getTitle(),
xml=xml_a,domain=publication) 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 : else :
# If slow sync, then resend everything # If slow sync, then resend everything
if alert_code == self.SLOW_SYNC: if alert_code == self.SLOW_SYNC:
...@@ -103,8 +159,7 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -103,8 +159,7 @@ class PublicationSynchronization(XMLSyncUtils):
# Check if the last time synchronization is the same as the client one # Check if the last time synchronization is the same as the client one
mess='\nsubscriber.getNextAnchor:\t%s\nsubscriber.getLastAnchor:\t%s\ mess='\nsubscriber.getNextAnchor:\t%s\nsubscriber.getLastAnchor:\t%s\
\nlast_anchor:\t\t\t%s\nnext_anchor:\t\t\t%s' % (subscriber.getNextAnchor(), \nlast_anchor:\t\t\t%s\nnext_anchor:\t\t\t%s' % (subscriber.getNextAnchor(), subscriber.getLastAnchor(), last_anchor, next_anchor)
subscriber.getLastAnchor(), last_anchor, next_anchor)
LOG('PubSyncInit',0,mess) LOG('PubSyncInit',0,mess)
if subscriber.getNextAnchor() != last_anchor: if subscriber.getNextAnchor() != last_anchor:
...@@ -112,8 +167,8 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -112,8 +167,8 @@ class PublicationSynchronization(XMLSyncUtils):
LOG('PubSyncInit',0,'anchor null') LOG('PubSyncInit',0,'anchor null')
raise ValueError, "Sorry, the anchor was null" raise ValueError, "Sorry, the anchor was null"
else: else:
message = "bad anchors in PubSyncInit! " + subscriber.getNextAnchor() + \ message = "bad anchors in PubSyncInit! " + \
" and " + last_anchor subscriber.getNextAnchor() + " and " + last_anchor
LOG('PubSyncInit',0,message) LOG('PubSyncInit',0,message)
else: else:
subscriber.setNextAnchor(next_anchor) subscriber.setNextAnchor(next_anchor)
...@@ -123,8 +178,7 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -123,8 +178,7 @@ class PublicationSynchronization(XMLSyncUtils):
# We have started the sync from the server (may be for a conflict resolution) # We have started the sync from the server (may be for a conflict resolution)
pass pass
if alert is not None and auth_required==0: if alert is not None and not publication.isAuthenticationRequired():
#if 1:
# Prepare the xml message for the Sync initialization package # Prepare the xml message for the Sync initialization package
cmd_id = 1 # specifies a SyncML message-unique command identifier cmd_id = 1 # specifies a SyncML message-unique command identifier
xml_list = [] xml_list = []
...@@ -203,7 +257,15 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -203,7 +257,15 @@ class PublicationSynchronization(XMLSyncUtils):
result = self.PubSyncInit(publication=publication, result = self.PubSyncInit(publication=publication,
xml_client=xml_client, subscriber=subscriber, sync_type=alert_code) xml_client=xml_client, subscriber=subscriber, sync_type=alert_code)
else: 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: elif subscriber is not None:
# This looks like we are starting a synchronization after # This looks like we are starting a synchronization after
# a conflict resolution by the user # a conflict resolution by the user
......
...@@ -41,6 +41,11 @@ from zLOG import LOG ...@@ -41,6 +41,11 @@ from zLOG import LOG
import md5 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, Implicit):
class Conflict(SyncCode, Base): class Conflict(SyncCode, Base):
""" """
...@@ -53,8 +58,8 @@ class Conflict(SyncCode, Base): ...@@ -53,8 +58,8 @@ class Conflict(SyncCode, Base):
isIndexable = 0 isIndexable = 0
isPortalContent = 0 # Make sure RAD generated accessors at the class level isPortalContent = 0 # Make sure RAD generated accessors at the class level
def __init__(self, object_path=None, keyword=None, xupdate=None, publisher_value=None,\ def __init__(self, object_path=None, keyword=None, xupdate=None,
subscriber_value=None, subscriber=None): publisher_value=None, subscriber_value=None, subscriber=None):
self.object_path=object_path self.object_path=object_path
self.keyword = keyword self.keyword = keyword
self.setLocalValue(publisher_value) self.setLocalValue(publisher_value)
...@@ -614,8 +619,8 @@ class Subscription(Folder, SyncCode): ...@@ -614,8 +619,8 @@ class Subscription(Folder, SyncCode):
isPortalContent = 1 isPortalContent = 1
isRADContent = 1 isRADContent = 1
icon = None icon = None
isIndexable = 0 isIndexable = 0
user = None
# Declarative properties # Declarative properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Base
...@@ -635,7 +640,8 @@ class Subscription(Folder, SyncCode): ...@@ -635,7 +640,8 @@ class Subscription(Folder, SyncCode):
) )
# Constructor # 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 We need to create a dictionnary of
signatures of documents which belong to the synchronisation signatures of documents which belong to the synchronisation
...@@ -652,6 +658,10 @@ class Subscription(Folder, SyncCode): ...@@ -652,6 +658,10 @@ class Subscription(Folder, SyncCode):
#self.signatures = PersistentMapping() #self.signatures = PersistentMapping()
self.last_anchor = '00000000T000000Z' self.last_anchor = '00000000T000000Z'
self.next_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.domain_type = self.SUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(None) self.setGidGenerator(None)
...@@ -714,28 +724,28 @@ class Subscription(Folder, SyncCode): ...@@ -714,28 +724,28 @@ class Subscription(Folder, SyncCode):
We will see if the last session id was the same We will see if the last session id was the same
wich means that the same message was sent again 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) last_session_id = getattr(self,'last_session_id',None)
if last_session_id == session_id: if last_session_id == session_id:
return 0 return False
self.last_session_id = session_id self.last_session_id = session_id
return 1 return True
def checkCorrectRemoteMessageId(self, message_id): def checkCorrectRemoteMessageId(self, message_id):
""" """
We will see if the last message id was the same We will see if the last message id was the same
wich means that the same message was sent again 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) last_message_id = getattr(self,'last_message_id',None)
# LOG('checkCorrectRemoteMessageId last_message_id =',0,last_message_id) # LOG('checkCorrectRemoteMessageId last_message_id =',0,last_message_id)
# LOG('checkCorrectRemoteMessageId message_id =',0,message_id) # LOG('checkCorrectRemoteMessageId message_id =',0,message_id)
if last_message_id == message_id: if last_message_id == message_id:
return 0 return False
self.last_message_id = message_id self.last_message_id = message_id
return 1 return True
def initLastMessageId(self, last_message_id=None): def initLastMessageId(self, last_message_id=None):
""" """
...@@ -872,25 +882,74 @@ class Subscription(Folder, SyncCode): ...@@ -872,25 +882,74 @@ class Subscription(Folder, SyncCode):
""" """
return self.gid_generator 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): def getGidFromObject(self, object):
""" """
""" """
o_base = aq_base(object) o_base = aq_base(object)
o_gid = None o_gid = None
# LOG('getGidFromObject',0,'gidgenerator : _%s_' % repr(self.getGidGenerator()))
gid_gen = self.getGidGenerator() gid_gen = self.getGidGenerator()
if callable(gid_gen): if callable(gid_gen):
# LOG('getGidFromObject gid_generator',0,'is callable')
o_gid=gid_gen(object) o_gid=gid_gen(object)
# LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
elif getattr(o_base, gid_gen, None) is not None: 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) generator = getattr(object, gid_gen)
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant 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: elif gid_gen is not None:
# It might be a script python # It might be a script python
# LOG('getGidFromObject',0,'there is the gid generator')
generator = getattr(object,gid_gen) generator = getattr(object,gid_gen)
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant
# LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid)) # LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
...@@ -911,7 +970,6 @@ class Subscription(Folder, SyncCode): ...@@ -911,7 +970,6 @@ class Subscription(Folder, SyncCode):
# LOG('getObjectFromGid oject_list',0,object_list) # LOG('getObjectFromGid oject_list',0,object_list)
if signature is not None and signature.getId() is not None: if signature is not None and signature.getId() is not None:
o_id = signature.getId() o_id = signature.getId()
# LOG('getObjectFromGid o_id',0,o_id)
o = None o = None
try: try:
o = destination._getOb(o_id) o = destination._getOb(o_id)
...@@ -920,7 +978,6 @@ class Subscription(Folder, SyncCode): ...@@ -920,7 +978,6 @@ class Subscription(Folder, SyncCode):
if o is not None and o in object_list: if o is not None and o in object_list:
return o return o
for o in object_list: for o in object_list:
# LOG('getObjectFromGid',0,'working on : %s' % repr(o))
o_gid = self.getGidFromObject(o) o_gid = self.getGidFromObject(o)
if o_gid == gid: if o_gid == gid:
return o return o
...@@ -1073,6 +1130,12 @@ class Subscription(Folder, SyncCode): ...@@ -1073,6 +1130,12 @@ class Subscription(Folder, SyncCode):
set the message id to 0 set the message id to 0
""" """
self.message_id = 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): def getLastAnchor(self):
""" """
...@@ -1230,3 +1293,67 @@ class Subscription(Folder, SyncCode): ...@@ -1230,3 +1293,67 @@ class Subscription(Folder, SyncCode):
o.setTempXML(None) o.setTempXML(None)
self.setRemainingObjectPathList(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
...@@ -44,6 +44,8 @@ class SubscriptionSynchronization(XMLSyncUtils): ...@@ -44,6 +44,8 @@ class SubscriptionSynchronization(XMLSyncUtils):
""" """
LOG('SubSyncInit',0,'starting....') LOG('SubSyncInit',0,'starting....')
cmd_id = 1 # specifies a SyncML message-unique command identifier cmd_id = 1 # specifies a SyncML message-unique command identifier
subscription.NewAnchor()
subscription.initLastMessageId()
xml_list = [] xml_list = []
xml = xml_list.append xml = xml_list.append
xml('<SyncML>\n') xml('<SyncML>\n')
...@@ -54,8 +56,6 @@ class SubscriptionSynchronization(XMLSyncUtils): ...@@ -54,8 +56,6 @@ class SubscriptionSynchronization(XMLSyncUtils):
# syncml body # syncml body
xml(' <SyncBody>\n') xml(' <SyncBody>\n')
subscription.NewAnchor()
subscription.initLastMessageId()
# We have to set every object as NOT_SYNCHRONIZED # We have to set every object as NOT_SYNCHRONIZED
subscription.startSynchronization() subscription.startSynchronization()
...@@ -100,7 +100,21 @@ class SubscriptionSynchronization(XMLSyncUtils): ...@@ -100,7 +100,21 @@ class SubscriptionSynchronization(XMLSyncUtils):
xml_client = msg xml_client = msg
if isinstance(xml_client, str) or isinstance(xml_client, unicode): if isinstance(xml_client, str) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client) 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: if RESPONSE is not None:
...@@ -108,6 +122,53 @@ class SubscriptionSynchronization(XMLSyncUtils): ...@@ -108,6 +122,53 @@ class SubscriptionSynchronization(XMLSyncUtils):
else: else:
return response 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): def SubSyncModif(self, subscription, xml_client):
""" """
Send the client modification, this happens after the Synchronization Send the client modification, this happens after the Synchronization
......
...@@ -62,8 +62,8 @@ from zLOG import LOG ...@@ -62,8 +62,8 @@ from zLOG import LOG
class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronization, class SynchronizationTool( SubscriptionSynchronization,
UniqueObject, Folder): PublicationSynchronization, UniqueObject, Folder):
""" """
This tool implements the synchronization algorithm This tool implements the synchronization algorithm
...@@ -159,9 +159,11 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -159,9 +159,11 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
+ '?manage_tabs_message=Tool+updated.' + '?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, 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 create a new publication
""" """
...@@ -171,7 +173,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -171,7 +173,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
folder = self.getObjectContainer() folder = self.getObjectContainer()
new_id = self.getPublicationIdFromTitle(title) new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path, 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 ) folder._setObject( new_id, pub )
#if len(self.list_publications) == 0: #if len(self.list_publications) == 0:
# self.list_publications = PersistentMapping() # self.list_publications = PersistentMapping()
...@@ -179,9 +182,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -179,9 +182,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_addSubscription') security.declareProtected(Permissions.ModifyPortalContent,
'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url, 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 XXX should be renamed as addSubscription
create a new subscription create a new subscription
...@@ -192,7 +198,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -192,7 +198,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
folder = self.getObjectContainer() folder = self.getObjectContainer()
new_id = self.getSubscriptionIdFromTitle(title) new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url, 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 ) folder._setObject( new_id, sub )
#if len(self.list_subscriptions) == 0: #if len(self.list_subscriptions) == 0:
# self.list_subscriptions = PersistentMapping() # self.list_subscriptions = PersistentMapping()
...@@ -200,10 +208,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -200,10 +208,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editPublication') security.declareProtected(Permissions.ModifyPortalContent,
'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path, def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, id_generator, 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 modify a publication
""" """
...@@ -217,13 +227,19 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -217,13 +227,19 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
pub.setGPGKey(gpg_key) pub.setGPGKey(gpg_key)
pub.setIdGenerator(id_generator) pub.setIdGenerator(id_generator)
pub.setGidGenerator(gid_generator) pub.setGidGenerator(gid_generator)
pub.setAuthentication(auth_required)
pub.setAuthenticationFormat(authentication_format)
pub.setAuthenticationType(authentication_type)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editSubscription') security.declareProtected(Permissions.ModifyPortalContent,
'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url, def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, id_generator, destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, RESPONSE=None): gid_generator,login='', password='', authentication_format='',
authentication_type='', RESPONSE=None):
""" """
modify a subscription modify a subscription
""" """
...@@ -238,10 +254,15 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -238,10 +254,15 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
sub.setSubscriptionUrl(subscription_url) sub.setSubscriptionUrl(subscription_url)
sub.setIdGenerator(id_generator) sub.setIdGenerator(id_generator)
sub.setGidGenerator(gid_generator) sub.setGidGenerator(gid_generator)
sub.setLogin(login)
sub.setPassword(password)
sub.setAuthenticationFormat(authentication_format)
sub.setAuthenticationType(authentication_type)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_deletePublication') security.declareProtected(Permissions.ModifyPortalContent,
'manage_deletePublication')
def manage_deletePublication(self, title, RESPONSE=None): def manage_deletePublication(self, title, RESPONSE=None):
""" """
delete a publication delete a publication
...@@ -252,7 +273,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -252,7 +273,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_deleteSubscription') security.declareProtected(Permissions.ModifyPortalContent,
'manage_deleteSubscription')
def manage_deleteSubscription(self, title, RESPONSE=None): def manage_deleteSubscription(self, title, RESPONSE=None):
""" """
delete a subscription delete a subscription
...@@ -263,7 +285,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -263,7 +285,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetPublication') security.declareProtected(Permissions.ModifyPortalContent,
'manage_resetPublication')
def manage_resetPublication(self, title, RESPONSE=None): def manage_resetPublication(self, title, RESPONSE=None):
""" """
reset a publication reset a publication
...@@ -273,7 +296,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -273,7 +296,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetSubscription') security.declareProtected(Permissions.ModifyPortalContent,
'manage_resetSubscription')
def manage_resetSubscription(self, title, RESPONSE=None): def manage_resetSubscription(self, title, RESPONSE=None):
""" """
reset a subscription reset a subscription
...@@ -284,7 +308,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -284,7 +308,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_syncSubscription') security.declareProtected(Permissions.ModifyPortalContent,
'manage_syncSubscription')
def manage_syncSubscription(self, title, RESPONSE=None): def manage_syncSubscription(self, title, RESPONSE=None):
""" """
reset a subscription reset a subscription
...@@ -293,7 +318,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -293,7 +318,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.AccessContentsInformation,'getPublicationList') security.declareProtected(Permissions.AccessContentsInformation,
'getPublicationList')
def getPublicationList(self): def getPublicationList(self):
""" """
Return a list of publications Return a list of publications
...@@ -303,7 +329,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -303,7 +329,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
object_list = filter(lambda x: x.id.find('pub')==0,object_list) object_list = filter(lambda x: x.id.find('pub')==0,object_list)
return object_list return object_list
security.declareProtected(Permissions.AccessContentsInformation,'getPublication') security.declareProtected(Permissions.AccessContentsInformation,
'getPublication')
def getPublication(self, title): def getPublication(self, title):
""" """
Return the publications with this id Return the publications with this id
...@@ -313,7 +340,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -313,7 +340,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
return p return p
return None return None
security.declareProtected(Permissions.AccessContentsInformation,'getObjectContainer') security.declareProtected(Permissions.AccessContentsInformation,
'getObjectContainer')
def getObjectContainer(self): def getObjectContainer(self):
""" """
this returns the external mount point if there is one this returns the external mount point if there is one
...@@ -325,7 +353,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -325,7 +353,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
folder = root.external_mount_point folder = root.external_mount_point
return folder return folder
security.declareProtected(Permissions.AccessContentsInformation,'getSubscriptionList') security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriptionList')
def getSubscriptionList(self): def getSubscriptionList(self):
""" """
Return a list of publications Return a list of publications
...@@ -345,7 +374,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -345,7 +374,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
return None return None
security.declareProtected(Permissions.AccessContentsInformation,'getSynchronizationList') security.declareProtected(Permissions.AccessContentsInformation,
'getSynchronizationList')
def getSynchronizationList(self): def getSynchronizationList(self):
""" """
Returns the list of subscriptions and publications Returns the list of subscriptions and publications
...@@ -353,7 +383,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -353,7 +383,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
""" """
return self.getSubscriptionList() + self.getPublicationList() return self.getSubscriptionList() + self.getPublicationList()
security.declareProtected(Permissions.AccessContentsInformation,'getSubscriberList') security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriberList')
def getSubscriberList(self): def getSubscriberList(self):
""" """
Returns the list of subscribers and subscriptions Returns the list of subscribers and subscriptions
...@@ -364,13 +395,15 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -364,13 +395,15 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
s_list += publication.getSubscriberList() s_list += publication.getSubscriberList()
return s_list return s_list
security.declareProtected(Permissions.AccessContentsInformation,'getConflictList') security.declareProtected(Permissions.AccessContentsInformation,
'getConflictList')
def getConflictList(self, context=None): def getConflictList(self, context=None):
""" """
Retrieve the list of all conflicts Retrieve the list of all conflicts
Here the list is as follow : Here the list is as follow :
[conflict_1,conflict2,...] where conflict_1 is like: [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) path = self.resolveContext(context)
conflict_list = [] conflict_list = []
...@@ -385,7 +418,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -385,7 +418,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
conflict_list += [conflict.__of__(subscriber)] conflict_list += [conflict.__of__(subscriber)]
for subscription in self.getSubscriptionList(): for subscription in self.getSubscriptionList():
sub_conflict_list = subscription.getConflictList() 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: for conflict in sub_conflict_list:
if isinstance(conflict,str): if isinstance(conflict,str):
import pdb; pdb.set_trace() import pdb; pdb.set_trace()
...@@ -402,7 +436,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -402,7 +436,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
# return new_list # return new_list
return conflict_list return conflict_list
security.declareProtected(Permissions.AccessContentsInformation,'getDocumentConflictList') security.declareProtected(Permissions.AccessContentsInformation,
'getDocumentConflictList')
def getDocumentConflictList(self, context=None): def getDocumentConflictList(self, context=None):
""" """
Retrieve the list of all conflicts for a given document Retrieve the list of all conflicts for a given document
...@@ -411,7 +446,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -411,7 +446,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
return self.getConflictList(context) return self.getConflictList(context)
security.declareProtected(Permissions.AccessContentsInformation,'getSynchronizationState') security.declareProtected(Permissions.AccessContentsInformation,
'getSynchronizationState')
def getSynchronizationState(self, context): def getSynchronizationState(self, context):
""" """
context : the context on which we are looking for state context : the context on which we are looking for state
...@@ -464,7 +500,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -464,7 +500,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
state_list += [[subscriber,state]] state_list += [[subscriber,state]]
return state_list return state_list
security.declareProtected(Permissions.ModifyPortalContent, 'applyPublisherValue') security.declareProtected(Permissions.ModifyPortalContent,
'applyPublisherValue')
def applyPublisherValue(self, conflict): def applyPublisherValue(self, conflict):
""" """
after a conflict resolution, we have decided after a conflict resolution, we have decided
...@@ -494,7 +531,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -494,7 +531,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
directory._delObject(copy_id) directory._delObject(copy_id)
signature.setStatus(self.PUB_CONFLICT_MERGE) signature.setStatus(self.PUB_CONFLICT_MERGE)
security.declareProtected(Permissions.ModifyPortalContent, 'applyPublisherDocument') security.declareProtected(Permissions.ModifyPortalContent,
'applyPublisherDocument')
def applyPublisherDocument(self, conflict): def applyPublisherDocument(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
...@@ -506,7 +544,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -506,7 +544,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
LOG('applyPublisherDocument, applying on conflict: ',0,conflict) LOG('applyPublisherDocument, applying on conflict: ',0,conflict)
c.applyPublisherValue() c.applyPublisherValue()
security.declareProtected(Permissions.AccessContentsInformation, 'getPublisherDocumentPath') security.declareProtected(Permissions.AccessContentsInformation,
'getPublisherDocumentPath')
def getPublisherDocumentPath(self, conflict): def getPublisherDocumentPath(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
...@@ -514,7 +553,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -514,7 +553,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
subscriber = conflict.getSubscriber() subscriber = conflict.getSubscriber()
return conflict.getObjectPath() return conflict.getObjectPath()
security.declareProtected(Permissions.AccessContentsInformation, 'getPublisherDocument') security.declareProtected(Permissions.AccessContentsInformation,
'getPublisherDocument')
def getPublisherDocument(self, conflict): def getPublisherDocument(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
...@@ -548,8 +588,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -548,8 +588,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
directory._delObject(object_id) directory._delObject(object_id)
# Import the conduit and get it # Import the conduit and get it
conduit_name = subscriber.getConduit() conduit_name = subscriber.getConduit()
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), ['']) conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
conduit = getattr(conduit_module, conduit_name)() globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id) conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id) subscriber_document = directory._getOb(object_id)
for c in self.getConflictList(conflict.getObjectPath()): for c in self.getConflictList(conflict.getObjectPath()):
...@@ -570,24 +611,33 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -570,24 +611,33 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
object_id = repotool._getId(docid, new_rev) object_id = repotool._getId(docid, new_rev)
return object_id return object_id
security.declareProtected(Permissions.AccessContentsInformation, 'getSubscriberDocumentPath') security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriberDocumentPath')
def getSubscriberDocumentPath(self, conflict): def getSubscriberDocumentPath(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
""" """
copy_path = conflict.getCopyPath() copy_path = conflict.getCopyPath()
if copy_path is not None: if copy_path is not None:
return copy_path return copy_path
subscriber = conflict.getSubscriber() subscriber = conflict.getSubscriber()
publisher_object_path = conflict.getObjectPath() publisher_object_path = conflict.getObjectPath()
publisher_object = self.unrestrictedTraverse(publisher_object_path) 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 directory = publisher_object.aq_inner.aq_parent
object_id = self._getCopyId(publisher_object) object_id = self._getCopyId(publisher_object)
# Import the conduit and get it # Import the conduit and get it
conduit_name = subscriber.getConduit() conduit_name = subscriber.getConduit()
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), ['']) if conduit_name.startswith('Products'):
conduit = getattr(conduit_module, conduit_name)() 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) conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id) subscriber_document = directory._getOb(object_id)
subscriber_document._conflict_resolution = 1 subscriber_document._conflict_resolution = 1
...@@ -598,7 +648,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -598,7 +648,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
conflict.setCopyPath(copy_path) conflict.setCopyPath(copy_path)
return copy_path return copy_path
security.declareProtected(Permissions.AccessContentsInformation, 'getSubscriberDocument') security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriberDocument')
def getSubscriberDocument(self, conflict): def getSubscriberDocument(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
...@@ -607,7 +658,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -607,7 +658,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
subscriber_object = self.unrestrictedTraverse(subscriber_object_path) subscriber_object = self.unrestrictedTraverse(subscriber_object_path)
return subscriber_object return subscriber_object
security.declareProtected(Permissions.ModifyPortalContent, 'applySubscriberDocument') security.declareProtected(Permissions.ModifyPortalContent,
'applySubscriberDocument')
def applySubscriberDocument(self, conflict): def applySubscriberDocument(self, conflict):
""" """
apply the subscriber value for all conflict of the given document apply the subscriber value for all conflict of the given document
...@@ -617,7 +669,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -617,7 +669,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if c.getSubscriber() == subscriber: if c.getSubscriber() == subscriber:
c.applySubscriberValue() c.applySubscriberValue()
security.declareProtected(Permissions.ModifyPortalContent, 'applySubscriberValue') security.declareProtected(Permissions.ModifyPortalContent,
'applySubscriberValue')
def applySubscriberValue(self, conflict,object=None): def applySubscriberValue(self, conflict,object=None):
""" """
after a conflict resolution, we have decided after a conflict resolution, we have decided
...@@ -636,7 +689,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -636,7 +689,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
signature = subscriber.getSignature(object.getId()) # XXX may be change for rid signature = subscriber.getSignature(object.getId()) # XXX may be change for rid
# Import the conduit and get it # Import the conduit and get it
conduit_name = subscriber.getConduit() 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)() conduit = getattr(conduit_module, conduit_name)()
for xupdate in conflict.getXupdateList(): for xupdate in conflict.getXupdateList():
conduit.updateNode(xml=xupdate,object=object,force=1) conduit.updateNode(xml=xupdate,object=object,force=1)
...@@ -656,15 +710,18 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -656,15 +710,18 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
directory._delObject(copy_id) directory._delObject(copy_id)
signature.setStatus(self.PUB_CONFLICT_MERGE) signature.setStatus(self.PUB_CONFLICT_MERGE)
security.declareProtected(Permissions.ModifyPortalContent, 'managePublisherValue') security.declareProtected(Permissions.ModifyPortalContent,
def managePublisherValue(self, subscription_url, property_id, object_path, RESPONSE=None): 'managePublisherValue')
def managePublisherValue(self, subscription_url, property_id, object_path,
RESPONSE=None):
""" """
Do whatever needed in order to store the local value on Do whatever needed in order to store the local value on
the remote server the remote server
Suggestion (API) Suggestion (API)
add method to view document with applied xupdate 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 Version=Version CPS
""" """
# Retrieve the conflict object # Retrieve the conflict object
...@@ -681,8 +738,10 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -681,8 +738,10 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageConflicts') RESPONSE.redirect('manageConflicts')
security.declareProtected(Permissions.ModifyPortalContent, 'manageSubscriberValue') security.declareProtected(Permissions.ModifyPortalContent,
def manageSubscriberValue(self, subscription_url, property_id, object_path, RESPONSE=None): 'manageSubscriberValue')
def manageSubscriberValue(self, subscription_url, property_id, object_path,
RESPONSE=None):
""" """
Do whatever needed in order to store the remote value locally Do whatever needed in order to store the remote value locally
and confirmed that the remote box should keep it's value and confirmed that the remote box should keep it's value
...@@ -700,7 +759,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -700,7 +759,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageConflicts') RESPONSE.redirect('manageConflicts')
security.declareProtected(Permissions.ModifyPortalContent, 'manageSubscriberDocument') security.declareProtected(Permissions.ModifyPortalContent,
'manageSubscriberDocument')
def manageSubscriberDocument(self, subscription_url, object_path): def manageSubscriberDocument(self, subscription_url, object_path):
""" """
""" """
...@@ -711,7 +771,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -711,7 +771,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
break break
self.managePublisherDocument(object_path) self.managePublisherDocument(object_path)
security.declareProtected(Permissions.ModifyPortalContent, 'managePublisherDocument') security.declareProtected(Permissions.ModifyPortalContent,
'managePublisherDocument')
def managePublisherDocument(self, object_path): def managePublisherDocument(self, object_path):
""" """
""" """
...@@ -742,7 +803,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -742,7 +803,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
return context.getPhysicalPath() return context.getPhysicalPath()
security.declarePublic('sendResponse') 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 We will look at the url and we will see if we need to send mail, http
response, or just copy to a file. response, or just copy to a file.
...@@ -760,7 +822,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -760,7 +822,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
decrypted.write(xml) decrypted.write(xml)
decrypted.close() decrypted.close()
(status,output)=commands.getstatusoutput('gzip /tmp/%s' % filename) (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) LOG('readResponse, gpg output:',0,output)
encrypted = file('/tmp/%s.gz.gpg' % filename,'r') encrypted = file('/tmp/%s.gz.gpg' % filename,'r')
xml = encrypted.read() xml = encrypted.read()
...@@ -775,7 +839,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -775,7 +839,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
return None return None
# we will send an http response # we will send an http response
domain = aq_base(domain) 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, self.activate(activity='RAMQueue').sendHttpResponse(sync_id=sync_id,
to_url=to_url, to_url=to_url,
xml=xml, domain=domain) xml=xml, domain=domain)
...@@ -814,7 +878,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -814,7 +878,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
pass_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() pass_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib2.HTTPBasicAuthHandler(pass_mgr) auth_handler = urllib2.HTTPBasicAuthHandler(pass_mgr)
proxy_auth_handler = urllib2.ProxyBasicAuthHandler(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) urllib2.install_opener(opener)
to_encode = {'text':xml,'sync_id':sync_id} to_encode = {'text':xml,'sync_id':sync_id}
encoded = urllib.urlencode(to_encode) encoded = urllib.urlencode(to_encode)
...@@ -825,7 +890,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -825,7 +890,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
try: try:
result = urllib2.urlopen(request).read() result = urllib2.urlopen(request).read()
except socket.error, msg: 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) LOG('sendHttpResponse, socket ERROR:',0,msg)
return return
...@@ -853,7 +919,6 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -853,7 +919,6 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
# Login as a manager to make sure we can create objects # Login as a manager to make sure we can create objects
uf = self.acl_users uf = self.acl_users
user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'') user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'')
#user = uf.getUserById('syncml').__of__(uf)
newSecurityManager(None, user) newSecurityManager(None, user)
message_list = self.portal_activities.getMessageList() message_list = self.portal_activities.getMessageList()
LOG('sync, message_list:',0,message_list) LOG('sync, message_list:',0,message_list)
...@@ -871,12 +936,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -871,12 +936,12 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
LOG('readResponse, ',0,'starting') LOG('readResponse, ',0,'starting')
LOG('readResponse, self.getPhysicalPath: ',0,self.getPhysicalPath()) LOG('readResponse, self.getPhysicalPath: ',0,self.getPhysicalPath())
LOG('readResponse, sync_id: ',0,sync_id) LOG('readResponse, sync_id: ',0,sync_id)
#LOG('readResponse, text:',0,text)
# Login as a manager to make sure we can create objects # Login as a manager to make sure we can create objects
uf = self.acl_users uf = self.acl_users
user = uf.getUserById('syncml').__of__(uf) user = uf.getUserById('syncml').__of__(uf)
user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'') user = UnrestrictedUser('syncml','syncml',['Manager','Member'],'')
newSecurityManager(None, user) newSecurityManager(None, user)
status_code = None
if text is not None: if text is not None:
# XXX We will look everywhere for a publication/subsription with # XXX We will look everywhere for a publication/subsription with
...@@ -896,46 +961,38 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -896,46 +961,38 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
encrypted = file('/tmp/%s.gz.gpg' % filename,'w') encrypted = file('/tmp/%s.gz.gpg' % filename,'w')
encrypted.write(text) encrypted.write(text)
encrypted.close() 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)) (status,output)=commands.getstatusoutput('gpg --homedir \
LOG('readResponse, gpg output:',0,output) /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) (status,output)=commands.getstatusoutput('gunzip /tmp/%s.gz' % filename)
decrypted = file('/tmp/%s' % filename,'r') decrypted = file('/tmp/%s' % filename,'r')
text = decrypted.read() text = decrypted.read()
LOG('readResponse, text:',0,text) LOG('readResponse, text:', 0, text)
decrypted.close() decrypted.close()
commands.getstatusoutput('rm -f /tmp/%s' % filename) commands.getstatusoutput('rm -f /tmp/%s' % filename)
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename) commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
# Get the target and then find the corresponding publication or # Get the target and then find the corresponding publication or
# Subscription # Subscription
LOG('readResponse, xml before parseSTring\n',0,text)
xml = parseString(text) xml = parseString(text)
#XXX this function is not very optimized and should be improved #XXX this function is not very optimized and should be improved
url = self.getTarget(xml) url = self.getTarget(xml)
for publication in self.getPublicationList(): 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) result = self.PubSync(sync_id,xml)
# Then encrypt the message # Then encrypt the message
xml = result['xml'] xml = result['xml']
#must be commented because this method is alredy called #must be commented because this method is alredy called
#xml = self.sendResponse(xml=xml,domain=publication,send=0) #xml = self.sendResponse(xml=xml,domain=publication,send=0)
return xml return xml
for subscription in self.getSubscriptionList(): for subscription in self.getSubscriptionList():
if subscription.getSubscriptionUrl()==url and \ if subscription.getSubscriptionUrl()==url and \
subscription.getTitle()==sync_id: subscription.getTitle()==sync_id:
next_status = self.getNextSyncBodyStatus(xml, None) result = self.activate(activity='RAMQueue').SubSync(sync_id,
if next_status is not None: text)
status_code = self.getStatusCode(next_status) #result = self.SubSync(sync_id,xml)
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)
# we use from only if we have a file # we use from only if we have a file
elif isinstance(from_url, str): elif isinstance(from_url, str):
...@@ -953,14 +1010,16 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -953,14 +1010,16 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
xml = None xml = None
return xml return xml
security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle') security.declareProtected(Permissions.ModifyPortalContent,
'getPublicationIdFromTitle')
def getPublicationIdFromTitle(self, title): def getPublicationIdFromTitle(self, title):
""" """
simply return an id from a title simply return an id from a title
""" """
return 'pub_' + title return 'pub_' + title
security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle') security.declareProtected(Permissions.ModifyPortalContent,
'getPublicationIdFromTitle')
def getSubscriptionIdFromTitle(self, title): def getSubscriptionIdFromTitle(self, title):
""" """
simply return an id from a title simply return an id from a title
...@@ -973,7 +1032,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati ...@@ -973,7 +1032,8 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
""" """
# Import the conduit and get it # Import the conduit and get it
from Products.ERP5SyncML import Conduit 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)() conduit_object = getattr(conduit_module, conduit)()
return conduit_object.addNode(**kw) return conduit_object.addNode(**kw)
......
...@@ -47,7 +47,8 @@ from zLOG import LOG ...@@ -47,7 +47,8 @@ from zLOG import LOG
class XMLSyncUtilsMixin(SyncCode): class XMLSyncUtilsMixin(SyncCode):
def SyncMLHeader(self, session_id, msg_id, target, source, target_name=None, 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 Since the Header is always almost the same, this is the
way to set one quickly. way to set one quickly.
...@@ -61,14 +62,22 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -61,14 +62,22 @@ class XMLSyncUtilsMixin(SyncCode):
xml(' <MsgID>%s</MsgID>\n' % msg_id) xml(' <MsgID>%s</MsgID>\n' % msg_id)
xml(' <Target>\n') xml(' <Target>\n')
xml(' <LocURI>%s</LocURI>\n' % target) 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(' <LocName>%s</LocName>\n' %target_name)
xml(' </Target>\n') xml(' </Target>\n')
xml(' <Source>\n') xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % source) 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(' <LocName>%s</LocName>\n' % source_name)
xml(' </Source>\n') 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(' </SyncHdr>\n')
xml_a = ''.join(xml_list) xml_a = ''.join(xml_list)
return xml_a return xml_a
...@@ -103,7 +112,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -103,7 +112,7 @@ class XMLSyncUtilsMixin(SyncCode):
return xml_a return xml_a
def SyncMLStatus(self, cmd_id, target_ref, source_ref, sync_code, 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 Since the Status section is always almost the same, this is the
way to set one quickly. way to set one quickly.
...@@ -115,13 +124,14 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -115,13 +124,14 @@ class XMLSyncUtilsMixin(SyncCode):
xml(' <TargetRef>%s</TargetRef>\n' % target_ref) xml(' <TargetRef>%s</TargetRef>\n' % target_ref)
xml(' <SourceRef>%s</SourceRef>\n' % source_ref) xml(' <SourceRef>%s</SourceRef>\n' % source_ref)
xml(' <Data>%s</Data>\n' % sync_code) xml(' <Data>%s</Data>\n' % sync_code)
xml(' <Item>\n') if next_anchor is not None:
xml(' <Data>\n') xml(' <Item>\n')
xml(' <Anchor xmlns=\'syncml:metinf\'>\n') xml(' <Data>\n')
xml(' <Next>%s</Next>\n' % next_anchor) xml(' <Anchor xmlns=\'syncml:metinf\'>\n')
xml(' </Anchor>\n') xml(' <Next>%s</Next>\n' % next_anchor)
xml(' </Data>\n') xml(' </Anchor>\n')
xml(' </Item>\n') xml(' </Data>\n')
xml(' </Item>\n')
xml(' </Status>\n') xml(' </Status>\n')
xml_a = ''.join(xml_list) xml_a = ''.join(xml_list)
return xml_a return xml_a
...@@ -416,27 +426,6 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -416,27 +426,6 @@ class XMLSyncUtilsMixin(SyncCode):
return int(subnode.childNodes[0].data) return int(subnode.childNodes[0].data)
return None 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): def getStatusCommand(self, xml):
""" """
Return the value of the command inside the xml_stream Return the value of the command inside the xml_stream
...@@ -448,6 +437,44 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -448,6 +437,44 @@ class XMLSyncUtilsMixin(SyncCode):
return subnode.childNodes[0].data return subnode.childNodes[0].data
return None 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): def getAlertCode(self, xml_stream):
""" """
Return the value of the alert code inside the full syncml message Return the value of the alert code inside the full syncml message
...@@ -739,13 +766,13 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -739,13 +766,13 @@ class XMLSyncUtilsMixin(SyncCode):
# object_gid = gid_generator() # object_gid = gid_generator()
force = 0 force = 0
if syncml_data.count('\n') < self.MAX_LINES and not object.id.startswith('.'): # If not we have to cut 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,'xml_mapping: %s' % str(domain.xml_mapping))
LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml))) #LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml)))
LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list)) #LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list))
LOG('getSyncMLData',0,'hasSignature: %s' % str(subscriber.hasSignature(object_gid))) #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,'alert_code == slowsync: %s' % str(self.getAlertCode(remote_xml)==self.SLOW_SYNC))
signature = subscriber.getSignature(object_gid) 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 # Here we first check if the object was modified or not by looking at dates
if signature is not None: if signature is not None:
signature.checkSynchronizationNeeded(object) signature.checkSynchronizationNeeded(object)
...@@ -774,7 +801,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -774,7 +801,7 @@ class XMLSyncUtilsMixin(SyncCode):
rest_string = xml_string[len(short_string):] rest_string = xml_string[len(short_string):]
#LOG('XMLSyncUtils',0,'rest_string: %s' % str(rest_string)) #LOG('XMLSyncUtils',0,'rest_string: %s' % str(rest_string))
i += 1 i += 1
LOG('getSyncMLData',0,'setPartialXML with: %s' % str(rest_string)) #LOG('getSyncMLData',0,'setPartialXML with: %s' % str(rest_string))
signature.setPartialXML(rest_string) signature.setPartialXML(rest_string)
status =self.PARTIAL status =self.PARTIAL
signature.setAction('Add') signature.setAction('Add')
...@@ -787,8 +814,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -787,8 +814,8 @@ class XMLSyncUtilsMixin(SyncCode):
elif signature.getStatus()==self.NOT_SYNCHRONIZED \ elif signature.getStatus()==self.NOT_SYNCHRONIZED \
or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet 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) xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping)
LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object))) #LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object)))
LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus())) #LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus()==self.PUB_CONFLICT_MERGE: if signature.getStatus()==self.PUB_CONFLICT_MERGE:
xml_confirmation += self.SyncMLConfirmation(cmd_id,object.id, xml_confirmation += self.SyncMLConfirmation(cmd_id,object.id,
self.CONFLICT_MERGE,'Replace') self.CONFLICT_MERGE,'Replace')
...@@ -821,7 +848,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -821,7 +848,7 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setTempXML(xml_object) signature.setTempXML(xml_object)
# Now we can apply the xupdate from the subscriber # Now we can apply the xupdate from the subscriber
subscriber_xupdate = signature.getSubscriberXupdate() subscriber_xupdate = signature.getSubscriberXupdate()
LOG('getSyncMLData subscriber_xupdate',0,subscriber_xupdate) #LOG('getSyncMLData subscriber_xupdate',0,subscriber_xupdate)
if subscriber_xupdate is not None: if subscriber_xupdate is not None:
old_xml = signature.getXML() old_xml = signature.getXML()
conduit.updateNode(xml=subscriber_xupdate, object=object, conduit.updateNode(xml=subscriber_xupdate, object=object,
...@@ -1080,7 +1107,6 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1080,7 +1107,6 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if xml_header.nodeName != "SyncHdr": if xml_header.nodeName != "SyncHdr":
LOG('PubSyncModif',0,'This is not a SyncML Header') LOG('PubSyncModif',0,'This is not a SyncML Header')
raise ValueError, "Sorry, 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 subscriber = domain # If we are the client, this is fine
simulate = 0 # used by applyActionList, should be 0 for client simulate = 0 # used by applyActionList, should be 0 for client
...@@ -1103,11 +1129,12 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1103,11 +1129,12 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if last_xml != '': if last_xml != '':
has_response = 1 has_response = 1
if domain.domain_type == self.PUB: # We always reply if domain.domain_type == self.PUB: # We always reply
self.sendResponse(from_url=domain.publication_url, to_url=subscriber.subscription_url, self.sendResponse(from_url=domain.publication_url,
sync_id=domain.getTitle(), xml=last_xml,domain=domain) to_url=subscriber.subscription_url, sync_id=domain.getTitle(),
xml=last_xml,domain=domain)
elif domain.domain_type == self.SUB: elif domain.domain_type == self.SUB:
self.sendResponse(from_url=domain.subscription_url, to_url=domain.publication_url, self.sendResponse(from_url=domain.subscription_url,
sync_id=domain.getTitle(), xml=last_xml,domain=domain) to_url=domain.publication_url, sync_id=domain.getTitle(), xml=last_xml,domain=domain)
return {'has_response':has_response,'xml':last_xml} return {'has_response':has_response,'xml':last_xml}
subscriber.setLastSentMessage('') subscriber.setLastSentMessage('')
...@@ -1135,7 +1162,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1135,7 +1162,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
subscriber=subscriber, subscriber=subscriber,
remote_xml=remote_xml, remote_xml=remote_xml,
conduit=conduit, simulate=simulate) 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_list = []
xml = xml_list.append xml = xml_list.append
......
...@@ -127,6 +127,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -127,6 +127,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" /> <input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td> </td>
</tr> </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>
<table> <table>
<tr> <tr>
......
...@@ -137,6 +137,46 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -137,6 +137,46 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" /> <input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td> </td>
</tr> </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>
<table> <table>
<tr> <tr>
......
...@@ -123,6 +123,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -123,6 +123,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" size="40" /> <input type="text" name="gid_generator" size="40" />
</td> </td>
</tr> </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> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
</td> </td>
......
...@@ -134,6 +134,45 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -134,6 +134,45 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</td> </td>
</tr> </tr>
<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 align="left" valign="top">
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
......
...@@ -42,6 +42,10 @@ from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit ...@@ -42,6 +42,10 @@ from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from Products.ERP5SyncML.SyncCode import SyncCode from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG from zLOG import LOG
try:
from base64 import b64encode, b64decode
except ImportError:
from base64 import encodestring as b64encode, decodestring as b64decode
class TestERP5SyncML(ERP5TypeTestCase): class TestERP5SyncML(ERP5TypeTestCase):
# Different variables used for this test # Different variables used for this test
...@@ -51,7 +55,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -51,7 +55,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
last_name1 = 'Robin' last_name1 = 'Robin'
# At the beginning, I was using iso-8859-15 strings, but actually # At the beginning, I was using iso-8859-15 strings, but actually
# erp5 is using utf-8 everywhere # erp5 is using utf-8 everywhere
#description1 = 'description1 --- $sdfr_sdfsdf_oisfsopf' #description1 = 'description1 --- $sdfrç_sdfsçdf_oisfsopf'
description1 = 'description1 --- $sdfr\xc3\xa7_sdfs\xc3\xa7df_oisfsopf' description1 = 'description1 --- $sdfr\xc3\xa7_sdfs\xc3\xa7df_oisfsopf'
lang1 = 'fr' lang1 = 'fr'
format2 = 'html' format2 = 'html'
...@@ -59,12 +63,12 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -59,12 +63,12 @@ class TestERP5SyncML(ERP5TypeTestCase):
format4 = 'txt' format4 = 'txt'
first_name2 = 'Jean-Paul' first_name2 = 'Jean-Paul'
last_name2 = 'Smets' last_name2 = 'Smets'
#description2 = 'description2@ $*< <<< ----- >>>></title>&oekd' #description2 = 'description2éà@ $*< <<< ----- >>>></title>&oekd'
description2 = 'description2\xc3\xa9\xc3\xa0@ $*< <<< ----- >>>></title>&oekd' description2 = 'description2\xc3\xa9\xc3\xa0@ $*< <<< ----- >>>></title>&oekd'
lang2 = 'en' lang2 = 'en'
first_name3 = 'Yoshinori' first_name3 = 'Yoshinori'
last_name3 = 'Okuji' 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' 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^^^^]]]]]{{{{{{{'
description4 = 'description4 sdflkmooo^^^^]]]]]{{{{{{{' description4 = 'description4 sdflkmooo^^^^]]]]]{{{{{{{'
...@@ -182,10 +186,10 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -182,10 +186,10 @@ class TestERP5SyncML(ERP5TypeTestCase):
def login(self, quiet=0): def login(self, quiet=0):
uf = self.getPortal().acl_users uf = self.getPortal().acl_users
uf._doAddUser('seb', '', ['Manager'], []) uf._doAddUser('fab', 'myPassword', ['Manager'], [])
uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], []) uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], [])
uf._doAddUser('syncml', '', ['Manager'], []) uf._doAddUser('syncml', '', ['Manager'], [])
user = uf.getUserById('seb').__of__(uf) user = uf.getUserById('fab').__of__(uf)
newSecurityManager(None, user) newSecurityManager(None, user)
def populatePersonServer(self, quiet=0, run=run_all_test): def populatePersonServer(self, quiet=0, run=run_all_test):
...@@ -317,7 +321,6 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -317,7 +321,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
to define it here because it is specific to the unit testing to define it here because it is specific to the unit testing
""" """
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
#portal_sync.email = None # XXX To be removed
subscription = portal_sync.getSubscription(id) subscription = portal_sync.getSubscription(id)
publication = None publication = None
for publication in portal_sync.getPublicationList(): for publication in portal_sync.getPublicationList():
...@@ -984,7 +987,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -984,7 +987,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person_s.getDescription()==self.description3) self.failUnless(person_s.getDescription()==self.description3)
self.failUnless(person_c1.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 We will create conflicts with 3 differents nodes, and we will
solve it by taking one full version of documents. solve it by taking one full version of documents.
...@@ -1097,9 +1100,9 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -1097,9 +1100,9 @@ class TestERP5SyncML(ERP5TypeTestCase):
person_client1 = self.getPersonClient1() person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1) person1_c = person_client1._getOb(self.id1)
person2_c = person_client1._getOb(self.id2) 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_setLocalRoles('jp',['Manager','Owner'])
person2_s.manage_delLocalRoles(['seb']) person2_s.manage_delLocalRoles(['fab'])
self.synchronize(self.sub_id1) self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2) self.synchronize(self.sub_id2)
role_1_s = person1_s.get_local_roles() role_1_s = person1_s.get_local_roles()
...@@ -1182,7 +1185,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -1182,7 +1185,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
def test_30_GetSynchronizationType(self, quiet=0, run=run_all_test): def test_30_GetSynchronizationType(self, quiet=0, run=run_all_test):
# We will try to update some simple data, first # 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 run: return
if not quiet: if not quiet:
ZopeTestCase._print('\nTest Get Synchronization Type ') ZopeTestCase._print('\nTest Get Synchronization Type ')
...@@ -1257,20 +1260,20 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -1257,20 +1260,20 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.assertEqual(role_1_s,role_1_c) self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_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 run: return
if not quiet: if not quiet:
ZopeTestCase._print('\nTest Add One Way Subscription ') ZopeTestCase._print('\nTest Add One Way Subscription ')
LOG('Testing... ',0,'test_32_AddOneWaySubscription') LOG('Testing... ',0,'test_32_AddOneWaySubscription')
portal_id = self.getPortalId() portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1,self.publication_url, portal_sync.manage_addSubscription(self.sub_id1, self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues', self.subscription_url1, '/%s/person_client1' % portal_id,
'','ERP5Conduit','') 'objectValues', '', 'ERP5Conduit', '')
sub = portal_sync.getSubscription(self.sub_id1) sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None) 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 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 We want to make sure in this case that all modifications on the client
...@@ -1314,6 +1317,234 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -1314,6 +1317,234 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.assertEquals(person1_s.getFirstName(),self.first_name1) 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__': if __name__ == '__main__':
framework() framework()
......
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