def __init__(self, jid, use_id=False): """Tries to create a JID out of 'jid'. Raises an exception if the JID is malformed. """ if use_id: jid_number = jid res = None try: c = DBautocommit().cursor() c.execute("SELECT jid FROM jids WHERE id = %d" % (jid_number)) res = c.fetchone() except: logging.debug('JID: init from number failed') if res and len(res) > 0: jid = res[0] else: jid = '' m = JID.jidre.match(jid) if not m: raise Exception, '[JID] %s is not a proper JID' % jid self.node = m.group(2) self.domain = m.group(3) self.resource = m.group(5)
def getContactInfo(self, cjid, includeGroups=True): """Returns information about a contact with JID cjid in this user's roster. Returns a RosterItem if the contact exists in the roster; False otherwise. If includeGroups is True, groups are added to the RosterItem as well. """ con = DBautocommit() c = con.cursor() c.execute("SELECT roster.contactid, roster.name, roster.subscription\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE userid = ? AND jids.jid = ?", (self.uid, cjid)) res = c.fetchone() if res: cid = res[0] name = res[1] sub = res[2] else: c.close() return False if includeGroups: # get the groups c.execute("SELECT rgs.name\ FROM rostergroups AS rgs\ JOIN rostergroupitems AS rgi ON rgi.groupid = rgs.groupid\ WHERE rgs.userid = ? AND rgi.contactid = ?", (self.uid, cid)) groups = [group['name'] for group in c] return RosterItem(cjid, name, sub, groups, cid) else: return RosterItem(cjid, name, sub, id=cid)
def exists(self): """Returns True if this JID exists in the DB""" c = DBautocommit().cursor() c.execute("SELECT jid FROM jids WHERE jid = ? AND password != ''", (self.getBare(),)) res = c.fetchone() if res: return True else: return False
def exists(self): """Returns True if this JID exists in the DB""" c = DBautocommit().cursor() c.execute("SELECT jid FROM jids WHERE jid = ? AND password != ''", (self.getBare(), )) res = c.fetchone() if res: return True else: return False
def getSubscription(self, cid): """Returns the subscription id of this user's contact with id cid""" con = DBautocommit() c = con.cursor() c.execute("SELECT subscription FROM roster\ WHERE userid = ? AND contactid = ?", (self.uid, cid)) res = c.fetchone() if res: sub = res[0] return sub else: raise Exception, "No such contact in roster"
def getSubscription(self, cid): """Returns the subscription id of this user's contact with id cid""" con = DBautocommit() c = con.cursor() c.execute( "SELECT subscription FROM roster\ WHERE userid = ? AND contactid = ?", (self.uid, cid)) res = c.fetchone() if res: sub = res[0] return sub else: raise Exception, "No such contact in roster"
def exists(self): """Returns True if this JID exists in the DB""" res = None try: c = DBautocommit().cursor() c.execute("SELECT jid FROM jids WHERE jid = ? AND password != ''", (self.getBare(),)) res = c.fetchone() except: logging.debug('JID: check existence failed') if res: return True else: return False
def getNumId(self): """Returns this JID's database numeric ID""" res = None try: c = DBautocommit().cursor() c.execute("SELECT id FROM jids WHERE jid = ?", (self.getBare(),)) res = c.fetchone() except: logging.debug('JID: get numeric ID failed') if res and len(res) > 0: return res[0] else: return -1
def getSubPrimaryName(self, cid): """Gets the primary name of a subscription for this user and this contact suitable for including in the subscription attribute of a roster's item element. """ con = DBautocommit() c = con.cursor() c.execute("SELECT subscription FROM roster\ WHERE roster.userid = ? AND roster.contactid = ?", (self.uid, cid)) res = c.fetchone() if res is None: sub = 'none' else: sub = Subscription.getPrimaryNameFromState(res[0]) return sub
def handle(self, username, digest): con = DBautocommit() c = con.cursor() c.execute("SELECT password FROM jids WHERE \ jid = ?", (username + '@%s' % self.msg.conn.server.hostname, )) res = c.fetchone() if res: password = res[0] else: c.close() con.close() raise IQAuthError c.close() con.close() s = sha1() s.update(self.streamid + password) hashtext = s.hexdigest() if hashtext == digest: d = self.msg.conn.data d['user']['jid'] = '%s@%s' % (username, self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID( d['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() return else: raise IQAuthError
def getSubPrimaryName(self, cid): """Gets the primary name of a subscription for this user and this contact suitable for including in the subscription attribute of a roster's item element. """ con = DBautocommit() c = con.cursor() c.execute( "SELECT subscription FROM roster\ WHERE roster.userid = ? AND roster.contactid = ?", (self.uid, cid)) res = c.fetchone() if res is None: sub = 'none' else: sub = Subscription.getPrimaryNameFromState(res[0]) return sub
def __init__(self, jid): """Initializes the roster object, but does not fetch any roster-specific data from the DB. It checks if the jid exists in the roster and raises an exception if it doesn't. jid -- textual representation of a bare JID. """ self.items = {} self.jid = jid con = DBautocommit() c = con.cursor() # get our own id c.execute("SELECT id FROM jids WHERE jid = ?", (self.jid,)) res = c.fetchone() if res is None: raise Exception, "No record of this JID in the DB" self.uid = res[0]
def getPresenceSubscriptions(self): """Returns a list of JIDs of contacts of this user to whom the user is subscribed (to/both). """ con = DBautocommit() c = con.cursor() c.execute("SELECT jids.jid\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE roster.userid = ? AND\ roster.subscription IN (?, ?, ?)", (self.uid, Subscription.TO, Subscription.TO_PENDING_IN, Subscription.BOTH)) jids = [] res = c.fetchall() for row in res: jids.append(row[0]) return jids
def getPresenceSubscribers(self): """Returns a list of JIDs of contacts of this user who are interested in the user's presence info (from/both). """ con = DBautocommit() c = con.cursor() c.execute("SELECT jids.jid\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE roster.userid = ? AND\ roster.subscription IN (?, ?, ?)", (self.uid, Subscription.FROM, Subscription.FROM_PENDING_OUT, Subscription.BOTH)) jids = [] res = c.fetchall() for row in res: jids.append(row[0]) return jids
def __init__(self, jid): """Initializes the roster object, but does not fetch any roster-specific data from the DB. It checks if the jid exists in the roster and raises an exception if it doesn't. jid -- textual representation of a bare JID. """ self.items = {} self.jid = jid con = DBautocommit() c = con.cursor() # get our own id c.execute("SELECT id FROM jids WHERE jid = ?", (self.jid, )) res = c.fetchone() if res is None: raise Exception, "No record of this JID in the DB" self.uid = res[0]
def getPresenceSubscribers(self): """Returns a list of JIDs of contacts of this user who are interested in the user's presence info (from/both). """ con = DBautocommit() c = con.cursor() c.execute( "SELECT jids.jid\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE roster.userid = ? AND\ roster.subscription IN (?, ?, ?)", (self.uid, Subscription.FROM, Subscription.FROM_PENDING_OUT, Subscription.BOTH)) jids = [] res = c.fetchall() for row in res: jids.append(row[0]) return jids
def getPresenceSubscriptions(self): """Returns a list of JIDs of contacts of this user to whom the user is subscribed (to/both). """ con = DBautocommit() c = con.cursor() c.execute( "SELECT jids.jid\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE roster.userid = ? AND\ roster.subscription IN (?, ?, ?)", (self.uid, Subscription.TO, Subscription.TO_PENDING_IN, Subscription.BOTH)) jids = [] res = c.fetchall() for row in res: jids.append(row[0]) return jids
def handle(self, username, digest): con = DBautocommit() c = con.cursor() c.execute("SELECT password FROM jids WHERE \ jid = ?", (username + '@%s' % self.msg.conn.server.hostname,)) res = c.fetchone() if res: password = res[0] else: c.close() con.close() raise IQAuthError c.close() con.close() s = sha1() s.update(self.streamid + password) hashtext = s.hexdigest() if hashtext == digest: d = self.msg.conn.data d['user']['jid'] = '%s@%s' % (username, self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID(d['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() return else: raise IQAuthError
def getContactInfo(self, cjid, includeGroups=True): """Returns information about a contact with JID cjid in this user's roster. Returns a RosterItem if the contact exists in the roster; False otherwise. If includeGroups is True, groups are added to the RosterItem as well. """ con = DBautocommit() c = con.cursor() c.execute( "SELECT roster.contactid, roster.name, roster.subscription\ FROM roster\ JOIN jids ON jids.id = roster.contactid\ WHERE userid = ? AND jids.jid = ?", (self.uid, cjid)) res = c.fetchone() if res: cid = res[0] name = res[1] sub = res[2] else: c.close() return False if includeGroups: # get the groups c.execute( "SELECT rgs.name\ FROM rostergroups AS rgs\ JOIN rostergroupitems AS rgi ON rgi.groupid = rgs.groupid\ WHERE rgs.userid = ? AND rgi.contactid = ?", (self.uid, cid)) groups = [group['name'] for group in c] return RosterItem(cjid, name, sub, groups, cid) else: return RosterItem(cjid, name, sub, id=cid)
def handle(self, b64text): """Verify the username/password in response""" authtext = '' if b64text: try: authtext = fromBase64(b64text) except: raise SASLIncorrectEncodingError auth = authtext.split('\x00') if len(auth) != 3: raise SASLIncorrectEncodingError con = DBautocommit() c = con.cursor() c.execute("SELECT * FROM jids WHERE \ jid = ? AND password = ?" , (auth[1] + \ '@' + self.msg.conn.server.hostname, auth[2])) res = c.fetchall() if len(res) == 0: c.close() con.close() raise SASLAuthError c.close() con.close() self.msg.conn.data['sasl']['complete'] = True self.msg.conn.data['sasl']['in-progress'] = False self.msg.conn.data['user']['jid'] = '%s@%s' % ( auth[1], self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID( self.msg.conn.data['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() return Element('success', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-sasl'})
def handle(self, b64text): """Verify the username/password in response""" authtext = '' if b64text: try: authtext = fromBase64(b64text) except: raise SASLIncorrectEncodingError auth = authtext.split('\x00') if len(auth) != 3: raise SASLIncorrectEncodingError con = DBautocommit() c = con.cursor() c.execute("SELECT * FROM jids WHERE \ jid = ? AND password = ?", (auth[1] + \ '@' + self.msg.conn.server.hostname, auth[2])) res = c.fetchall() if len(res) == 0: c.close() con.close() raise SASLAuthError c.close() con.close() self.msg.conn.data['sasl']['complete'] = True self.msg.conn.data['sasl']['in-progress'] = False self.msg.conn.data['user']['jid'] = '%s@%s' % (auth[1], self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID(self.msg.conn.data['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() return Element('success', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-sasl'})
def handle(self, data=None): """Performs DIGEST-MD5 auth based on current state. data -- either None for initial challenge, base64-encoded text when the client responds to challenge 1, or the tree when the client responds to challenge 2. """ # TODO: authz # TODO: subsequent auth qop = 'qop="auth"' charset = 'charset=utf-8' algo = 'algorithm=md5-sess' if self.state == SASLDigestMD5.INIT: # initial challenge self.nonce = generateId() self.state = SASLDigestMD5.SENT_CHALLENGE1 nonce = 'nonce="%s"' % self.nonce realm = 'realm="%s"' % self.realm res = Element('challenge', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-sasl'}) res.text = base64.b64encode(','.join([realm, qop, nonce, charset, algo])) return res elif self.state == SASLDigestMD5.SENT_CHALLENGE1 and data: # response to client's reponse (ie. challenge 2) try: text = fromBase64(data) except: raise SASLIncorrectEncodingError pairs = self._parse(text) try: username = pairs['username'] nonce = pairs['nonce'] realm = pairs['realm'] cnonce = pairs['cnonce'] nc = pairs['nc'] qop = pairs['qop'] response = pairs['response'] digest_uri = pairs['digest-uri'] except KeyError: self._handleFailure() raise SASLAuthError self.username = username # authz is ignored for now if nonce != self.nonce or realm != self.realm \ or int(nc, 16) != 1 or qop[0] != 'auth' or not response\ or not digest_uri: self._handleFailure() raise SASLAuthError # fetch the password now con = DBautocommit() c = con.cursor() c.execute("SELECT password FROM jids WHERE \ jid = ?", (username + '@%s' % self.msg.conn.server.hostname,)) for row in c: password = row['password'] break else: self._handleFailure() c.close() con.close() raise SASLAuthError c.close() con.close() # compute the digest as per RFC 2831 a1 = "%s:%s:%s" % (H("%s:%s:%s" % (username, realm, password)), nonce, cnonce) a2 = ":%s" % digest_uri a2client = "AUTHENTICATE:%s" % digest_uri digest = HEX(KD(HEX(H(a1)), "%s:%s:%s:%s:%s" % (nonce, nc, cnonce, "auth", HEX(H(a2client))))) if digest == response: rspauth = HEX(KD(HEX(H(a1)), "%s:%s:%s:%s:%s" % (nonce, nc, cnonce, "auth", HEX(H(a2))))) self.state = SASLDigestMD5.SENT_CHALLENGE2 res = Element('challenge', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-sasl'}) res.text = base64.b64encode(u"rspauth=%s" % rspauth) return res else: self._handleFailure() raise SASLAuthError elif self.state == SASLDigestMD5.SENT_CHALLENGE2 and isinstance(data, Element): # expect to get <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> respInd = data.tag.find('{urn:ietf:params:xml:ns:xmpp-sasl}response') d = self.msg.conn.data if respInd != -1 and len(data) == 0: self.state = SASLDigestMD5.INIT d['sasl']['complete'] = True d['sasl']['in-progress'] = False d['user']['jid'] = '%s@%s' % (self.username, self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID(d['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() res = Element('success', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-sasl'}) return res else: self._handleFailure() raise SASLAuthError else: self._handleFailure() raise SASLAuthError
def handle(self, data=None): """Performs DIGEST-MD5 auth based on current state. data -- either None for initial challenge, base64-encoded text when the client responds to challenge 1, or the tree when the client responds to challenge 2. """ # TODO: authz # TODO: subsequent auth qop = 'qop="auth"' charset = 'charset=utf-8' algo = 'algorithm=md5-sess' if self.state == SASLDigestMD5.INIT: # initial challenge self.nonce = generateId() self.state = SASLDigestMD5.SENT_CHALLENGE1 nonce = 'nonce="%s"' % self.nonce realm = 'realm="%s"' % self.realm res = Element('challenge', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-sasl'}) res.text = base64.b64encode(','.join( [realm, qop, nonce, charset, algo])) return res elif self.state == SASLDigestMD5.SENT_CHALLENGE1 and data: # response to client's reponse (ie. challenge 2) try: text = fromBase64(data) except: raise SASLIncorrectEncodingError pairs = self._parse(text) try: username = pairs['username'] nonce = pairs['nonce'] realm = pairs['realm'] cnonce = pairs['cnonce'] nc = pairs['nc'] qop = pairs['qop'] response = pairs['response'] digest_uri = pairs['digest-uri'] except KeyError: self._handleFailure() raise SASLAuthError self.username = username # authz is ignored for now if nonce != self.nonce or realm != self.realm \ or int(nc, 16) != 1 or qop[0] != 'auth' or not response\ or not digest_uri: self._handleFailure() raise SASLAuthError # fetch the password now con = DBautocommit() c = con.cursor() c.execute( "SELECT password FROM jids WHERE \ jid = ?", (username + '@%s' % self.msg.conn.server.hostname, )) for row in c: password = row['password'] break else: self._handleFailure() c.close() con.close() raise SASLAuthError c.close() con.close() # compute the digest as per RFC 2831 a1 = "%s:%s:%s" % (H("%s:%s:%s" % (username, realm, password)), nonce, cnonce) a2 = ":%s" % digest_uri a2client = "AUTHENTICATE:%s" % digest_uri digest = HEX( KD( HEX(H(a1)), "%s:%s:%s:%s:%s" % (nonce, nc, cnonce, "auth", HEX(H(a2client))))) if digest == response: rspauth = HEX( KD( HEX(H(a1)), "%s:%s:%s:%s:%s" % (nonce, nc, cnonce, "auth", HEX(H(a2))))) self.state = SASLDigestMD5.SENT_CHALLENGE2 res = Element('challenge', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-sasl'}) res.text = base64.b64encode(u"rspauth=%s" % rspauth) return res else: self._handleFailure() raise SASLAuthError elif self.state == SASLDigestMD5.SENT_CHALLENGE2 and isinstance( data, Element): # expect to get <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> respInd = data.tag.find( '{urn:ietf:params:xml:ns:xmpp-sasl}response') d = self.msg.conn.data if respInd != -1 and len(data) == 0: self.state = SASLDigestMD5.INIT d['sasl']['complete'] = True d['sasl']['in-progress'] = False d['user']['jid'] = '%s@%s' % (self.username, self.msg.conn.server.hostname) # record the JID for local delivery self.msg.conn.server.conns[self.msg.conn.id] = (JID( d['user']['jid']), self.msg.conn) self.msg.conn.parser.resetParser() res = Element('success', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-sasl'}) return res else: self._handleFailure() raise SASLAuthError else: self._handleFailure() raise SASLAuthError