#!/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):
    active = 1
    revocationTime = None
    
    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 activate(self):
        if self.revocationTime:
            raise 'not in a valid state to be activated'
        self.active = 1
        self.revocationTime = None

    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)
                    try:
                        if not electionsProxy.hasObject(electionId):
                            del voteTokens[electionId]
                            continue
                    except faults.UnknownServerId:
                        continue

                    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 reactivate(self):
        if not self.revocationTime:
            raise 'not in a valid state to be reactivated'
        self.active = 1
        self.revocationTime = None

    def revoke(self):
        if not self.active:
            raise 'not in a valid state to be revoked'
        self.active = 0
        self.revocationDate = time.time()

    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 canDeleteObject(self, objectId):
        if objectId == self.getUserId():
            return 1
        return objects.ObjectsServer.canDeleteObject(self, objectId)

    def canGetAdmin(self):
        return self.isAdmin()

    def canModifyObject(self, objectId):
        if objectId == self.getUserId():
            return 1
        return objects.ObjectsServer.canModifyObject(self, objectId)

    def changeStatus(self, objectId, statusAction):
        if objectId != self.getUserId():
            return faults.UserAccessDenied()

        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        object = virtualServer.loadObjectCore(objectId)

        if statusAction == 'activation':
            object.activate()
        elif statusAction == 'reactivation':
            object.reactivate()
        elif statusAction == 'revocation':
            object.revoke()
        else:
            print 'Unknown status action:', statusAction

        
    def checkIdentityLocalNameIdentifierSP(
            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 checkIdentityPeerNameIdentifierSP(
            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 checkIdentityLocalNameIdentifierIDP(
            self, peerHostName, localNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        for object in virtualServer.objects.values():
            if object.serviceIdentifications is not None:
                for serviceIdentification in object.serviceIdentifications:
                    if serviceIdentification.peerHostName == peerHostName \
                            and serviceIdentification.localNameIdentifier \
                                    == localNameIdentifier:
                        return virtualServer.getObjectToken(object)
        raise faults.WrongNameIdentifier(localNameIdentifier)

    def checkIdentityPeerNameIdentifierIDP(
            self, peerHostName, peerNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        for object in virtualServer.objects.values():
            if object.serviceIdentifications is not None:
                for serviceIdentification in object.serviceIdentifications:
                    if serviceIdentification.peerHostName == peerHostName \
                            and serviceIdentification.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()

            admin = virtualServer.admin
            peopleAdmin = peopleVirtualServer.admin
            for attr in ('adminsSet', 'writersSet', 'readersSet'):
                if hasattr(peopleAdmin, attr):
                    setattr(admin, attr, getattr(peopleAdmin, attr))
            virtualServer.markAdminAsDirty(virtualServer.admin)

            preferencesPickleFilePath = os.path.join(
                    virtualServer.dataDirectoryPath,
                    'PreferencesServer.pickle')
            hasPreferences = 0
            if os.access(preferencesPickleFilePath, 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()

            virtualServer.markCoreAsDirty()

            personIds = peopleVirtualServer.objects.keys()
            personIds.sort(
                lambda x,y: cmp(
                    int(commonTools.extractLocalId(x)),
                    int(commonTools.extractLocalId(y)) ))

            if personIds:
                virtualServer.nextLocalId = int(commonTools.extractLocalId(
                        personIds[-1])) + 1

            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.id =  '%s/%s' % (
                        commonTools.makeApplicationId(personId,
                                'identities'),
                        commonTools.extractLocalId(personId))
                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 getLocalNameIdentifierIdentityProvider(self, peerHostName):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        if object.serviceIdentifications is not None:
            for serviceIdentification in object.serviceIdentifications:
                if serviceIdentification.peerHostName==peerHostName:
                    return serviceIdentification.localNameIdentifier
        return None

    def getLocalNameIdentifierServiceProvider(self, peerHostName):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        if object.identityIdentifications is not None:
            for identityIdentification in object.identityIdentifications:
                if identityIdentification.peerHostName==peerHostName:
                    return identityIdentification.localNameIdentifier
        return None

    def getObjectEmail(self, objectId):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        object = virtualServer.loadObjectCore(objectId)
        if not object.personId:
            return ''

        from glasnost.proxy.tools import getProxy
        personProxy = getProxy(object.personId)
        return personProxy.getObjectEmail(object.personId)


    def getObjectLabelAndLanguageXmlRpc(self, objectId):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        object = virtualServer.loadObjectCore(objectId)
        if not object.personId:
            return [object.getLabel(), '']

        from glasnost.proxy.tools import getProxy
        personProxy = getProxy(object.personId)
        return personProxy.getObjectLabelAndLanguage(object.personId)

    def getPeerNameIdentifierIdentityProvider(self, peerHostName):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        if object.serviceIdentifications is not None:
            for serviceIdentification in object.serviceIdentifications:
                if serviceIdentification.peerHostName==peerHostName:
                    return serviceIdentification.peerNameIdentifier
        return None

    def getPeerNameIdentifierServiceProvider(self, peerHostName):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        if object.identityIdentifications is not None:
            for identityIdentification in object.identityIdentifications:
                if identityIdentification.peerHostName==peerHostName:
                    return identityIdentification.peerNameIdentifier
        return None

    def getPersonId(self):
        userId = self.getUserId()

        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        identity = virtualServer.loadObjectCore(userId)

        return identity.personId

    def getPrivateKeySSL(self):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        admin = virtualServer.admin
        if admin.symetricKey is None:
            raise faults.MissingItem('Private Key for SSL')
        return admin.privateKeySSL

    def getRoles(self):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        admin = virtualServer.admin
        return admin.identitiesRoles

    def getSymetricKey(self):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        admin = virtualServer.admin
        if admin.symetricKey is None:
            raise faults.MissingItem('Symetric Key')
        return admin.symetricKey

    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', 'tokenaccounts',
                    'x509accounts']:
            raise faults.ApplicationAccessDenied(clientId)
        object = virtualServer.loadObjectCore(id)
        if clientRole != 'tokenaccounts' and not object.active:
            raise faults.DisabledAccount()
        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('changeStatus')
        self.registerPublicMethod('checkIdentityLocalNameIdentifierIDP')
        self.registerPublicMethod('checkIdentityLocalNameIdentifierSP')
        self.registerPublicMethod('checkIdentityPeerNameIdentifierIDP')
        self.registerPublicMethod('checkIdentityPeerNameIdentifierSP')
        self.registerPublicMethod('deleteUserToken')
        self.registerPublicMethod('getElectionVoteToken')
        self.registerPublicMethod('getLocalNameIdentifierIdentityProvider')
        self.registerPublicMethod('getLocalNameIdentifierServiceProvider')
        self.registerPublicMethod('getObjectEmail')
        self.registerPublicMethod('getPeerNameIdentifierIdentityProvider')
        self.registerPublicMethod('getPeerNameIdentifierServiceProvider')
        self.registerPublicMethod('getPersonId')
        self.registerPublicMethod('getPrivateKeySSL')
        self.registerPublicMethod('getRoles')
        self.registerPublicMethod('getSymetricKey')
        self.registerPublicMethod('getUserId')
        self.registerPublicMethod('getUserToken')
        self.registerPublicMethod('rememberId')
        self.registerPublicMethod('setContainsUser')
        self.registerPublicMethod('setLocalNameIdentifierIdentityProvider')
        self.registerPublicMethod('setLocalNameIdentifierServiceProvider')
        self.registerPublicMethod('setPeerNameIdentifierIdentityProvider')
        self.registerPublicMethod('setPeerNameIdentifierServiceProvider')

        self.registerPublicMethod('vote')

    def rememberId(self, id):
        virtualServerId = context.getVar('applicationId')
        if virtualServerId in ['glasnost://help/identities',
                               'glasnost://system/identities']:
            return
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        serverRole = commonTools.extractRole(id)
        object = virtualServer.loadObjectCore(userId)
        if type(object.objectsMemory) is not type({}):
            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 setLocalNameIdentifierIdentityProvider(
            self, peerHostName, newLocalNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]

        if object.serviceIdentifications is not None:
            for serviceIdentification in object.serviceIdentifications:
                if serviceIdentification.peerHostName==peerHostName:
                    serviceIdentification.localNameIdentifier = \
                                                         newLocalNameIdentifier
                    virtualServer.markObjectAsDirty(object)
                    invalidateValue(object.id)
                    return newLocalNameIdentifier
        return None

    def setLocalNameIdentifierServiceProvider(
            self, peerHostName, newLocalNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        
        if object.identityIdentifications is not None:
            for identityIdentification in object.identityIdentifications:
                if identityIdentification.peerHostName==peerHostName:
                    identityIdentification.localNameIdentifier = \
                                                         newLocalNameIdentifier
                    virtualServer.markObjectAsDirty(object)
                    invalidateValue(object.id)
                    return newLocalNameIdentifier
        return None

    def setPeerNameIdentifierIdentityProvider(self, peerHostName,
            newPeerNameIdentifier, oldPeerNameIdentifier,
            idpProvidedNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]
        
        if object.serviceIdentifications is not None:
            for identification in object.serviceIdentifications:
                if oldPeerNameIdentifier==idpProvidedNameIdentifier:
                    if identification.peerHostName==peerHostName and \
                       identification.localNameIdentifier==idpProvidedNameIdentifier:
                       identification.peerNameIdentifier = newPeerNameIdentifier
                else:
                    if identification.peerHostName==peerHostName and \
                           identification.peerNameIdentifier==oldPeerNameIdentifier:
                        identification.peerNameIdentifier = newPeerNameIdentifier
                        return newPeerNameIdentifier
        return None

    def setPeerNameIdentifierServiceProvider(
        self, peerHostName, newPeerNameIdentifier, oldPeerNameIdentifier):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        userId = self.getUserId()
        object = virtualServer.objects[userId]

        if object.identityIdentifications is not None:
            for identification in object.identityIdentifications:
                if identification.peerHostName==peerHostName and \
                      identification.peerNameIdentifier==oldPeerNameIdentifier:
                    identification.peerNameIdentifier = newPeerNameIdentifier
                    return newPeerNameIdentifier
        return None

    def sortObjectIds(self, objectIds, sortRule):
        # duplicated here since getLabel() is expensive on Identities
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        if not objectIds:
            objectIds = virtualServer.objects.keys()
        else:
            objectIds = [x for x in objectIds \
                         if virtualServer.objects.has_key(x)]

        if sortRule == 'id':
            objectIds.sort(lambda x,y: cmp(
                    int(commonTools.extractLocalId(x)),
                    int(commonTools.extractLocalId(y))) )
            return objectIds

        labels = [(x, virtualServer.objects[x].getLabel()) for x in objectIds]
        labels.sort(lambda x,y: cmp(x[1], x[1]))
        objectIds = [x[0] for x in labels]
        return objectIds


    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)

