412 lines
17 KiB
Python
Executable File
412 lines
17 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: iso-8859-15 -*-
|
|
|
|
|
|
# Glasnost
|
|
# By: Odile Bénassy <obenassy@entrouvert.com>
|
|
# Romain Chantereau <rchantereau@entrouvert.com>
|
|
# Nicolas Clapiès <nclapies@easter-eggs.org>
|
|
# Pierre-Antoine Dejace <padejace@entrouvert.be>
|
|
# Thierry Dulieu <tdulieu@easter-eggs.com>
|
|
# Florent Monnier <monnier@codelutin.com>
|
|
# Cédric Musso <cmusso@easter-eggs.org>
|
|
# Frédéric Péters <fpeters@entrouvert.be>
|
|
# Benjamin Poussin <poussin@codelutin.com>
|
|
# Emmanuel Raviart <eraviart@entrouvert.com>
|
|
# Sébastien Régnier <regnier@codelutin.com>
|
|
# Emmanuel Saracco <esaracco@easter-eggs.com>
|
|
#
|
|
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
|
|
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
|
|
# Emmanuel Saracco & Théridion
|
|
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
|
|
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
|
|
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
|
|
# Régnier, Emmanuel Saracco, Théridion & Vecam
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
__doc__ = """Glasnost Identities Server"""
|
|
|
|
__version__ = '$Revision$'[11:-2]
|
|
|
|
|
|
import md5
|
|
import sys
|
|
import time
|
|
import whrandom
|
|
|
|
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
|
|
sys.path.insert(0, glasnostPythonDir)
|
|
|
|
import glasnost
|
|
|
|
import glasnost.common.context as context
|
|
import glasnost.common.faults as faults
|
|
import glasnost.common.IdentitiesCommon as commonIdentities
|
|
import glasnost.common.tools_new as commonTools
|
|
|
|
import glasnost.server.ObjectsServer as objects
|
|
import glasnost.server.things as things
|
|
|
|
from glasnost.proxy.CacheProxy import invalidateValue
|
|
from glasnost.proxy.DispatcherProxy import getApplicationId
|
|
from glasnost.proxy.GroupsProxy import setContains
|
|
from glasnost.proxy.tools import getProxy
|
|
|
|
|
|
applicationName = 'IdentitiesServer'
|
|
applicationRole = 'identities'
|
|
dispatcher = None
|
|
|
|
# Don't forget to also change the value in SessionsServer.py.
|
|
expirationTime = 120 * 60
|
|
|
|
|
|
# FIXME: those classes are necessary to upgrade data from
|
|
# PeopleServer.pickle & PreferencesServer.pickle; they should be removed as
|
|
# soon as it is no longer necessary to access these files.
|
|
class AdminPeople: pass
|
|
class PeopleVirtualServer: pass
|
|
class Person: pass
|
|
class PreferencesVirtualServer: pass
|
|
|
|
|
|
class AdminIdentities(objects.AdminServerMixin,
|
|
commonIdentities.AdminIdentities):
|
|
pass
|
|
objects.register(AdminIdentities)
|
|
|
|
|
|
class Identification(things.ThingMixin, commonIdentities.Identification):
|
|
pass
|
|
things.register(Identification)
|
|
|
|
|
|
class Identity(objects.ObjectServerMixin, commonIdentities.Identity):
|
|
def abstainForVote(self, electionId):
|
|
if self.voteTokens is not None and self.voteTokens.has_key(electionId):
|
|
del self.voteTokens[electionId]
|
|
if len(self.voteTokens) == 0:
|
|
del self.voteTokens
|
|
|
|
def exportToXmlRpc(self, requiredSlotNames = None, parentSlot = None):
|
|
identityExport = commonIdentities.Identity.exportToXmlRpc(
|
|
self, requiredSlotNames = requiredSlotNames,
|
|
parentSlot = parentSlot)
|
|
|
|
userId = self.getServer().getUserId()
|
|
if self.id != userId and identityExport.has_key('voteTokens'):
|
|
if not userId:
|
|
del identityExport['voteTokens']
|
|
else:
|
|
voteTokens = identityExport['voteTokens'].copy()
|
|
for electionId, voteToken in voteTokens.items():
|
|
electionsProxy = getProxy(electionId)
|
|
if not electionsProxy.hasObject(electionId):
|
|
del voteTokens[electionId]
|
|
else:
|
|
electionBallotKind = electionsProxy.getBallotKind(
|
|
electionId)
|
|
if electionBallotKind == 'secret' \
|
|
or electionBallotKind == 'voterChoice' \
|
|
and getProxyForServerRole(
|
|
'ballots').isVoteSecret(voteToken):
|
|
voteTokens[electionId] = 'secret'
|
|
if len(voteTokens) == 0:
|
|
del identityExport['voteTokens']
|
|
else:
|
|
identityExport['voteTokens'] = voteTokens
|
|
return identityExport
|
|
|
|
def vote(self, electionId, voteToken):
|
|
if self.voteTokens is None:
|
|
self.voteTokens = {}
|
|
self.voteTokens[electionId] = voteToken
|
|
objects.register(Identity)
|
|
|
|
|
|
class IdentitiesVirtualServer(objects.ObjectsVirtualServer):
|
|
idsByToken = None
|
|
tokenExpirationTimes = None
|
|
|
|
def convertIds(self, sourceDispatcherId, destinationDispatcherId):
|
|
objects.ObjectsVirtualServer.convertIds(
|
|
self, sourceDispatcherId, destinationDispatcherId)
|
|
|
|
for token, expiration in self.tokenExpirationTimes.items():
|
|
newToken = token.replace(sourceDispatcherId,
|
|
destinationDispatcherId)
|
|
if newToken != token:
|
|
del self.tokenExpirationTimes[token]
|
|
self.tokenExpirationTimes[newToken] = expiration
|
|
|
|
for token, id in self.idsByToken.items():
|
|
newToken = token.replace(sourceDispatcherId,
|
|
destinationDispatcherId)
|
|
if newToken != token:
|
|
del self.idsByToken[token]
|
|
token = newToken
|
|
self.idsByToken[token] = id
|
|
newId = id.replace(sourceDispatcherId, destinationDispatcherId)
|
|
if newId != id:
|
|
self.idsByToken[token] = newId
|
|
|
|
def getObjectToken(self, object):
|
|
self.removeExpiredTokens()
|
|
|
|
self.lock.acquire()
|
|
for token, id in self.idsByToken.items():
|
|
if id == object.id:
|
|
objectToken = token
|
|
self.tokenExpirationTimes[token] = time.time() + expirationTime
|
|
break
|
|
else:
|
|
server = context.getVar('server')
|
|
while 1:
|
|
randomSalt = str(server.randomGenerator.uniform(0.1, 1))[2:]
|
|
digest = md5.new(randomSalt)
|
|
localToken = digest.hexdigest()
|
|
objectToken = '%s/%s' % (self.virtualServerId, localToken)
|
|
if not self.idsByToken.has_key(objectToken):
|
|
break
|
|
self.idsByToken[objectToken] = object.id
|
|
self.tokenExpirationTimes[objectToken] = time.time() \
|
|
+ expirationTime
|
|
self.lock.release()
|
|
self.markCoreAsDirty()
|
|
return objectToken
|
|
|
|
def init(self):
|
|
objects.ObjectsVirtualServer.init(self)
|
|
self.idsByToken = {}
|
|
self.tokenExpirationTimes = {}
|
|
|
|
def removeExpiredTokens(self):
|
|
currentTime = time.time()
|
|
removed = 0
|
|
self.lock.acquire()
|
|
for token in self.tokenExpirationTimes.keys():
|
|
if currentTime > self.tokenExpirationTimes[token]:
|
|
removed = 1
|
|
del self.idsByToken[token]
|
|
del self.tokenExpirationTimes[token]
|
|
self.lock.release()
|
|
if removed:
|
|
self.markCoreAsDirty()
|
|
|
|
|
|
class IdentitiesServer(commonIdentities.IdentitiesCommonMixin,
|
|
objects.ObjectsServer):
|
|
VirtualServer = IdentitiesVirtualServer
|
|
|
|
def abstainForVote(self, electionId):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
voterId = self.getUserId()
|
|
object = virtualServer.loadObjectCore(voterId)
|
|
object.abstainForVote(electionId)
|
|
virtualServer.markObjectAsDirty(object)
|
|
invalidateValue(object.id)
|
|
|
|
def checkIdentityLocalNameIdentifier(
|
|
self, peerHostName, localNameIdentifier):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
for object in virtualServer.objects.values():
|
|
if object.identityIdentifications is not None:
|
|
for identityIdentification in object.identityIdentifications:
|
|
if identityIdentification.peerHostName == peerHostName \
|
|
and identityIdentification.localNameIdentifier \
|
|
== localNameIdentifier:
|
|
return virtualServer.getObjectToken(object)
|
|
raise faults.WrongNameIdentifier(localNameIdentifier)
|
|
|
|
def checkIdentityPeerNameIdentifier(
|
|
self, peerHostName, peerNameIdentifier):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
for object in virtualServer.objects.values():
|
|
if object.identityIdentifications is not None:
|
|
for identityIdentification in object.identityIdentifications:
|
|
if identityIdentification.peerHostName == peerHostName \
|
|
and identityIdentification.peerNameIdentifier \
|
|
== peerNameIdentifier:
|
|
return virtualServer.getObjectToken(object)
|
|
raise faults.WrongNameIdentifier(peerNameIdentifier)
|
|
|
|
def deleteUserToken(self):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
userToken = context.getVar('userToken')
|
|
if virtualServer.idsByToken.has_key(userToken):
|
|
del virtualServer.idsByToken[userToken]
|
|
del virtualServer.tokenExpirationTimes[userToken]
|
|
|
|
def fillEmptyVirtualServer(self, virtualServer):
|
|
objects.ObjectsServer.fillEmptyVirtualServer(self, virtualServer)
|
|
|
|
# Upgrade to version 0001_0028.
|
|
import cPickle
|
|
import os
|
|
peoplePickleFilePath = os.path.join(virtualServer.dataDirectoryPath,
|
|
'PeopleServer.pickle')
|
|
if os.access(peoplePickleFilePath, os.F_OK):
|
|
print 'Importing PeopleServer data for %s.' \
|
|
% virtualServer.virtualServerId
|
|
peopleRcFile = open(peoplePickleFilePath, 'rb')
|
|
peopleVersion = self.readFileVersion(peopleRcFile)
|
|
peopleVirtualServer = cPickle.load(peopleRcFile)
|
|
peopleRcFile.close()
|
|
|
|
preferencesPickleFilePath = os.path.join(
|
|
virtualServer.dataDirectoryPath,
|
|
'PreferencesServer.pickle')
|
|
hasPreferences = 0
|
|
if os.access(peoplePickleFilePath, os.F_OK):
|
|
hasPreferences = 1
|
|
print 'Importing PreferencesServer data for %s.' \
|
|
% virtualServer.virtualServerId
|
|
preferencesRcFile = open(preferencesPickleFilePath, 'rb')
|
|
preferencesVersion = self.readFileVersion(preferencesRcFile)
|
|
preferencesVirtualServer = cPickle.load(preferencesRcFile)
|
|
preferencesRcFile.close()
|
|
|
|
personIds = peopleVirtualServer.objects.keys()
|
|
personIds.sort() # PasswordAccountsServer uses the same order.
|
|
for personId in personIds:
|
|
person = peopleVirtualServer.objects[personId]
|
|
identity = Identity()
|
|
identity.personId = personId
|
|
if hasattr(person, 'voteTokens'):
|
|
identity.voteTokens = person.voteTokens
|
|
if hasPreferences \
|
|
and preferencesVirtualServer.objects.has_key(personId):
|
|
preference = preferencesVirtualServer.objects[personId]
|
|
if preference.has_key('objectsMemory'):
|
|
identity.objectsMemory = preference['objectsMemory']
|
|
if preference.has_key('spellcheckEntries'):
|
|
identity.objectsMemory = preference[
|
|
'spellcheckEntries']
|
|
identity.setAutomaticalSlots()
|
|
virtualServer.objects[identity.id] = identity
|
|
identity.saveNonCore()
|
|
identity.releaseNonCore()
|
|
virtualServer.markObjectAsDirty(identity)
|
|
virtualServer.markCoreAsDirty()
|
|
|
|
def getElectionVoteToken(self, electionId):
|
|
clientToken = context.getVar('clientToken')
|
|
clientId = getApplicationId(clientToken)
|
|
clientRole = commonTools.extractRole(clientId)
|
|
if clientRole != 'ballots':
|
|
raise faults.UserAccessDenied()
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
voterId = self.getUserId()
|
|
object = virtualServer.loadObjectCore(voterId)
|
|
if object.voteTokens is None \
|
|
or not object.voteTokens.has_key(electionId):
|
|
raise faults.MissingItem(electionId)
|
|
return object.voteTokens[electionId]
|
|
|
|
def getUserId(self):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
userToken = context.getVar('userToken')
|
|
|
|
virtualServer.removeExpiredTokens()
|
|
if not virtualServer.idsByToken.has_key(userToken):
|
|
return ''
|
|
virtualServer.tokenExpirationTimes[userToken] = time.time() \
|
|
+ expirationTime
|
|
virtualServer.markCoreAsDirty()
|
|
return virtualServer.idsByToken[userToken]
|
|
|
|
def getUserToken(self, id):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
clientToken = context.getVar('clientToken')
|
|
clientId = getApplicationId(clientToken)
|
|
clientRole = commonTools.extractRole(clientId)
|
|
if not clientRole in ['passwordaccounts', 'x509accounts']:
|
|
raise faults.ApplicationAccessDenied(clientId)
|
|
object = virtualServer.loadObjectCore(id)
|
|
return virtualServer.getObjectToken(object)
|
|
|
|
def init(self):
|
|
self.randomGenerator = whrandom.whrandom()
|
|
objects.ObjectsServer.init(self)
|
|
|
|
def registerPublicMethods(self):
|
|
objects.ObjectsServer.registerPublicMethods(self)
|
|
self.registerPublicMethod('abstainForVote')
|
|
self.registerPublicMethod('checkIdentityLocalNameIdentifier')
|
|
self.registerPublicMethod('checkIdentityPeerNameIdentifier')
|
|
self.registerPublicMethod('deleteUserToken')
|
|
self.registerPublicMethod('getElectionVoteToken')
|
|
self.registerPublicMethod('getUserId')
|
|
self.registerPublicMethod('getUserToken')
|
|
self.registerPublicMethod('rememberId')
|
|
self.registerPublicMethod('setContainsUser')
|
|
self.registerPublicMethod('vote')
|
|
|
|
def rememberId(self, id):
|
|
virtualServerId = context.getVar('applicationId')
|
|
if virtualServerId == 'glasnost://system/identities':
|
|
return
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
userId = self.getUserId()
|
|
serverRole = commonTools.extractRole(id)
|
|
object = virtualServer.loadObjectCore(userId)
|
|
if object.objectsMemory is None:
|
|
object.objectsMemory = {}
|
|
objectsMemory = object.objectsMemory
|
|
if objectsMemory.has_key(serverRole):
|
|
serverMemory = objectsMemory[serverRole]
|
|
else:
|
|
serverMemory = None
|
|
if serverMemory is None:
|
|
serverMemory = objectsMemory[serverRole] = []
|
|
if id in serverMemory:
|
|
serverMemory.remove(id)
|
|
serverMemory.insert(0, id)
|
|
if len(serverMemory) > 10:
|
|
del serverMemory[10:]
|
|
virtualServer.markObjectAsDirty(object)
|
|
invalidateValue(object.id)
|
|
|
|
def setContainsUser(self, set):
|
|
return setContains(set, self.getUserId())
|
|
|
|
def vote(self, electionId, voteToken):
|
|
virtualServerId = context.getVar('applicationId')
|
|
virtualServer = self.getVirtualServer(virtualServerId)
|
|
voterId = self.getUserId()
|
|
object = virtualServer.loadObjectCore(voterId)
|
|
object.vote(electionId, voteToken)
|
|
virtualServer.markObjectAsDirty(object)
|
|
invalidateValue(object.id)
|
|
|
|
|
|
identitiesServer = IdentitiesServer()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
identitiesServer.launch(applicationName, applicationRole)
|