def createAccount(self, sid, login, passwd, nick, email): log.message('Creating account', login, nick, email) # check limit if len(self.accounts.keys()) > 2: raise SecurityException("No room for another account") # check login, nick and uid for key in self.accounts.keys(): account = self.accounts[key] if account.login == login: raise SecurityException('Login already used.') elif account.nick == nick: raise SecurityException('Nick already used.') elif account.email == email: raise SecurityException('E-mail already used.') # create account account = Account() # update account.login = login account.passwd = passwd account.nick = nick account.email = email account.confToken = md5.new('%s%s%d' % (login, email, time.time())).hexdigest() self.accounts[account.login] = account self.nick2login[account.nick] = account.login log.message('Account created, confirmation token:', account.confToken) # TODO send confirmation token to the email address return 1, None
def login(self, sid, login, cpasswd, hostID): # use metaserver if possible if self.metaserver is not None and login != ADMIN_LOGIN: challenge = self.sessions[sid].challenge log.debug("ClientMngr", "Verifying login data on metaserver") valid = self.metaserver.metasrvr.verifyUser(self.metaserverSID, login, challenge, cpasswd, False) log.debug("ClientMngr", "RPC call finished, result =", valid) if not valid: raise SecurityException("Wrong login and/or password") # set local session nick = self.metaserver.metasrvr.getUserNick(self.metaserverSID, login) self.sessions[sid].setAttrs(login, nick) return 1, None # standard login procedure login = login.strip() if not login: raise SecurityException("Specify login, please.") if login in (): raise SecurityException("Account blocked") log.debug(sid, 'login', repr(login), 'hostid', hostID) login = str(login) if not self.accounts.has_key(login): raise SecurityException('Wrong login and/or password.') account = self.accounts[login] challenge = self.sessions[sid].challenge if hashlib.sha512(account.passwd + challenge).hexdigest() != cpasswd: raise SecurityException('Wrong login and/or password.') self.sessions[sid].setAttrs(account.login, account.nick) account.lastLogin = time.time() account.addHostID(hostID) return 1, None
def changePassword(self, sid, old, new): session = self.sessions[sid] if session: if self.accounts[session.login].passwd == old: self.accounts[session.login].passwd = new return 1, None else: raise SecurityException('Wrong password.') else: raise SecurityException('No such session id.')
def login(self, sid, login, cpasswd, hostID): log.debug(sid, 'login', login, 'hostid', hostID) if not self.accounts.has_key(login): raise SecurityException('Wrong login and/or password.') account = self.accounts[login] challenge = self.sessions[sid].challenge if hashlib.sha512(account.passwd + challenge).hexdigest() != cpasswd: raise SecurityException('Wrong login and/or password (PLAIN).') self.sessions[sid].setAttrs(account.login, account.nick, account.email) account.lastLogin = time.time() account.addHostID(hostID) return 1, None
def changePassword(self, sid, safeOld, safeNew): session = self.sessions[sid] if not session: raise SecurityException('No such session id.') challenge = session.challenge account = self.accounts[session.login] oldPassword = Authentication.unwrapUserPassword(safeOld, challenge) newPassword = Authentication.unwrapUserPassword(safeNew, challenge) if not account.verifyPassword(oldPassword): raise SecurityException('Wrong login and/or password.') if len(newPassword) < ige.Const.ACCOUNT_PASSWD_MIN_LEN: raise SecurityException('Password is too short.') account.setPassword(newPassword) log.debug('Password of account {0} successfully changed.'.format(session.login)) return None, None
def createAccount(self, sid, login, passwd, nick, email): # use metaserver if possible if self.metaserver is not None: try: self.metaserver.account.create(login, passwd, nick, email) except xmlrpclib.Fault, e: raise SecurityException(e.faultString) return 1, None
def unwrapUserPassword(password, challenge): """Decode password according to auth method (if possible)""" method = getMethod(challenge) if method == "sha256": return password elif method == "rsa": return rsa.decrypt(binascii.unhexlify(password), getPrivateKey()) raise SecurityException("Unsupported authentication method %s" % str(method))
def getWelcomeString(method = "rsa"): """Return welcome string (typically a challenge)""" if method == "sha256": return "sha256:" + hashlib.sha256(str(time.time())).hexdigest() elif method == "rsa": publicKey = getPublicKey() return "rsa:%s:%s" % (publicKey.n, publicKey.e) raise SecurityException("Unsupported authentication method %s" % str(method))
def serverShutdown(self, sid): # check admin session = self.getSession(sid) if session.login != ADMIN_LOGIN: raise SecurityException('You cannot issue this command.') log.message('Shutting down server') import ige.RPCServer ige.RPCServer.running = 0 return 1, None
def encode(password, challenge): """Encode password using auth method specified in the challenge""" method = getMethod(challenge) if method == "sha256": return hashlib.sha256(password + challenge).hexdigest() elif method == "rsa": dummy, n, e = challenge.split(":") key = rsa.PublicKey(int(n), int(e)) return binascii.hexlify(rsa.encrypt(password.encode('utf-8'), key)) raise SecurityException("Unsupported authentication method %s" % str(method))
def logout(self, sid): session = self.sessions.get(sid, None) if session: try: log.debug(sid, 'logout', self.sessions[sid].login) except AttributeError: pass del self.sessions[sid] return 1, None else: raise SecurityException('No such session id.')
def login(self, sid, login, safePassword, hostID): login = login.strip() if not login: raise SecurityException("Specify login, please.") if login in (): raise SecurityException("Account blocked") log.debug(sid, 'login', repr(login), 'hostid', hostID) login = str(login) challenge = self.sessions[sid].challenge log.debug("Trying local login for user", login) if not self.accounts.has_key(login): raise SecurityException('Wrong login and/or password.') account = self.accounts[login] plainPassword = Authentication.unwrapUserPassword(safePassword, challenge) if not account.verifyPassword(plainPassword): raise SecurityException('Wrong login and/or password.') # setup session self.sessions[sid].setAttrs(account.login, account.nick, account.email) account.lastLogin = time.time() account.addHostID(hostID) return 1, None
def createAccount(self, sid, login, safePasswd, nick, email): log.message('Creating account', login, nick, email) session = self.getSession(sid) plainPassword = Authentication.unwrapUserPassword( safePasswd, session.challenge) login = login.strip() plainPassword = plainPassword.strip() nick = nick.strip() # check requirement if len(login) < ige.Const.ACCOUNT_LOGIN_MIN_LEN: raise SecurityException('Login is too short.') if len(plainPassword) < ige.Const.ACCOUNT_PASSWD_MIN_LEN: raise SecurityException('Password is too short.') if len(nick) < ige.Const.ACCOUNT_NICK_MIN_LEN: raise SecurityException('Nick is too short.') # check login, nick and uid for key in self.accounts.keys(): account = self.accounts[key] if account.login == login: raise SecurityException('Login already used.') elif account.nick == nick: raise SecurityException('Nick already used.') elif account.email == email: raise SecurityException('E-mail already used.') # create account account = account.Account(login, nick, email, plainPassword) # update self.accounts.create(account, id=str(account.login)) log.message('Account created, confirmation token:', account.confToken) # TODO send confirmation token to the email address return 1, None
def exportAccounts(self, sid): # check admin session = self.getSession(sid) if session.login != ADMIN_LOGIN: raise SecurityException('You cannot issue this command.') # export accounts f = open(os.path.join(self.configDir, "accounts.txt"), "w") for account in self.accounts.keys(): account = self.accounts[account] print >> f, "%s\t%s\t%s\t%s" % ( account.nick.encode("utf-8"), account.login.encode("utf-8"), account.passwd.encode("utf-8"), account.email.encode("utf-8")) f.close() return None, None
def cleanupSessions(self, sid): session = self.sessions.get(sid, None) if session: log.debug('cleaning up sessions') now = time.time() deleted = 0 for id in self.sessions.keys(): if self.sessions[id].timeout < now: del self.sessions[id] deleted += 1 log.debug('cleanup finished (%d active, %d deleted)' % (len(self.sessions), deleted)) return None, None else: raise SecurityException('No such session id.')
def takeOverPirate(self, sid, playerID, vipPassword): # limit this now only to the qark session = self.clientMngr.getSession(sid) player = self.db[playerID] if vipPassword != self.config.vip.password: raise SecurityException('Wrong VIP password.') if player.galaxy in self.accountGalaxies(session.login): raise GameException('Account already owns player in this galaxy.') if player.galaxy: galaxy = self.db[player.galaxy] if galaxy.scenario == Const.SCENARIO_SINGLE: raise GameException( 'AI in single scenario cannot be taken over.') log.debug('Creating pirate in session {0} with CID {1}'.format( sid, session.cid)) universe = self.db[Const.OID_UNIVERSE] log.debug('Creating transaction') tran = Transaction(self, session.cid, session) # create player #log.debug("Morphing Pirate player", playerID) log.debug("Player type", player.type) if player.type != Const.T_AIPIRPLAYER: raise GameException('No such starting position.') player.type = Const.T_PIRPLAYER self.cmdPool[Const.T_PIRPLAYER].upgrade(tran, player) self.cmdPool[Const.T_PIRPLAYER].update(tran, player) # reregister player self.removePlayer(player.oid) player.fullName = "Pirate %s" % session.nick player.name = session.nick player.login = session.login self.registerPlayer(player.login, player, player.oid) # add player to the universe universe.players.append(playerID) # initial scan scannerPwr = Rules.techs[9002].scannerPwr for planetID in player.planets: planet = self.db[planetID] system = self.db[planet.compOf] system.scannerPwrs[player.oid] = scannerPwr log.debug('Processing scan phase') galaxy = tran.db[player.galaxy] self.cmdPool[Const.T_GALAXY].processSCAN2Phase(tran, galaxy, True) # save game info self.generateGameInfo() return player.oid, None
def exportAccounts(self, sid): # check admin session = self.getSession(sid) if session.login != "admin": raise SecurityException('You cannot issue this command.') # export accounts f = open("var/accounts.txt", "w") for account in self.accounts.keys(): if account == "**nick2login**": continue account = self.accounts[account] print >>f, "%s\t%s\t%s\t%s" % ( account.nick, account.login, account.passwd, account.email ) f.close() return None, None
def takeOverPirate(self, sid, playerID, vipPassword): # limit this now only to the qark session = self.clientMngr.getSession(sid) if vipPassword != self.config.vip.password: raise SecurityException('You cannot issue this command.') # log.debug('Creating pirate in session', sid) session = self.clientMngr.getSession(sid) log.debug('Creating pirate with CID', session.cid) universe = self.db[OID_UNIVERSE] log.debug('Creating transaction') tran = Transaction(self, session.cid, session) # create player #log.debug("Morphing Pirate player", playerID) player = self.db[playerID] log.debug("Player type", player.type) if player.type != T_AIPIRPLAYER: raise GameException('No such starting position.') player.type = T_PIRPLAYER self.cmdPool[T_PIRPLAYER].upgrade(tran, player) self.cmdPool[T_PIRPLAYER].update(tran, player) # reregister player self.removePlayer(player.oid) player.fullName = "Pirate %s" % session.nick player.name = session.nick player.login = session.login self.registerPlayer(player.login, player, player.oid) # add player to the universe universe.players.append(playerID) # initial scan scannerPwr = Rules.techs[9002].scannerPwr for planetID in player.planets: planet = self.db[planetID] system = self.db[planet.compOf] system.scannerPwrs[player.oid] = scannerPwr log.debug('Processing scan phase') galaxy = tran.db[player.galaxies[0]] self.cmdPool[T_GALAXY].processSCAN2Phase(tran, galaxy, None) # save game info self.generateGameInfo() return player.oid, None
def sendMsg(self, tran, obj, message): if tran.session.cid != Const.OID_ADMIN: message["sender"] = tran.session.nick message["senderID"] = tran.session.cid # check attributes if "forum" not in message: raise GameException("Forum not specified.") if message["forum"] not in self.forums: raise GameException("No such forum.") if "topic" not in message: raise GameException("Topic not specified.") if "data" not in message and "text" not in message: raise GameException("Text or structured data not specified.") # check permissions if tran.session.cid != Const.OID_ADMIN and \ not self.canSendMsg(tran, obj, message["senderID"], message["forum"]): raise SecurityException("You cannot send message to this entity.") # message["recipient"] = obj.name message["recipientID"] = obj.oid # send message return tran.gameMngr.msgMngr.send(tran.gameMngr.gameID, obj.oid, message)
def getMsgs(self, tran, obj, lastID = -1): if not self.canGetMsgs(tran, obj, tran.session.cid): raise SecurityException("You cannot read messages of this entity.") # get messages return tran.gameMngr.msgMngr.get(tran.gameMngr.gameID, obj.oid, lastID)
class ClientMngr: def __init__(self, database): self._filename = os.path.join('var', 'accounts') self.sessions = {} self.metaserver = None # self.accounts = database # create nick to account mapping self.nick2login = database.get("**nick2login**", Mapping()) # create special key if not self.accounts.has_key(ADMIN_LOGIN): log.message("No administator account found! (looking for '%s')" % ADMIN_LOGIN) log.message("Creating default account") self.createAccount(None, ADMIN_LOGIN, "tobechanged", "Administrator", "*****@*****.**") password = sha.new(str(random.randrange(0, 1e10))).hexdigest() open(os.path.join("var", "token"), "w").write(password) self.accounts[ADMIN_LOGIN].passwd = password def setMetaserver(self, server, sid): self.metaserver = server self.metaserverSID = sid def shutdown(self): self.accounts.shutdown() def checkpoint(self): self.accounts.checkpoint() def backup(self, basename): self.accounts.backup(basename) def exists(self, login): return self.accounts.has_key(str(login)) def getAccountByNick(self, nick, default = None): if not self.nick2login.has_key(nick): return default return self.accounts[self.nick2login[str(nick)]] def __getitem__(self, login): return self.accounts[str(login)] def createAccount(self, sid, login, passwd, nick, email): # use metaserver if possible if self.metaserver is not None: try: self.metaserver.account.create(login, passwd, nick, email) except xmlrpclib.Fault, e: raise SecurityException(e.faultString) return 1, None # create local account log.message('Creating account', login, nick, email) login = login.strip() passwd = passwd.strip() nick = nick.strip() # check requirement if len(login) < 4: raise SecurityException('Login is too short.') if len(passwd) < 4: raise SecurityException('Password is too short.') if len(nick) < 4: raise SecurityException('Nick is too short.') # check login, nick and uid for key in self.accounts.keys(): account = self.accounts[key] if account.login == login: raise SecurityException('Login already used.') elif account.nick == nick: raise SecurityException('Nick already used.') elif account.email == email: raise SecurityException('E-mail already used.') # create account account = Account() # update account.login = login account.passwd = passwd account.nick = nick account.email = email account.confToken = md5.new('%s%s%d' % (login, email, time.time())).hexdigest() self.accounts.create(account, id = str(account.login)) self.nick2login[account.nick] = account.login log.message('Account created, confirmation token:', account.confToken) # TODO send confirmation token to the email address return 1, None
def deleteMsgs(self, tran, obj, ids): if not self.canManageMsgs(tran, obj, tran.session.cid): raise SecurityException("You cannot manage messages of this entity.") # get messages return tran.gameMngr.msgMngr.delete(tran.gameMngr.gameID, obj.oid, ids)
def getSession(self, sid): session = self.sessions.get(sid, None) if not session: raise SecurityException('No such session id.') return session