Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Alvaro Videla committed Jan 21, 2010
0 parents commit fc96564
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 0 deletions.
23 changes: 23 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Copyright (c) 2010 Alvaro Videla <videlalvaro@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


PHPUnserialize taken from http://hurring.com/code/python/phpserialize/
with modified version of session_decode by me
185 changes: 185 additions & 0 deletions PHPUnserialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import types, string, re

"""
Unserialize class for the PHP serialization format.
@version v0.4 BETA
@author Scott Hurring; scott at hurring dot com
@copyright Copyright (c) 2005 Scott Hurring
@license http://opensource.org/licenses/gpl-license.php GNU Public License
$Id: PHPUnserialize.py,v 1.1 2006/01/08 21:53:19 shurring Exp $
Most recent version can be found at:
http://hurring.com/code/python/phpserialize/
Usage:
# Create an instance of the unserialize engine
u = PHPUnserialize()
# unserialize some string into python data
data = u.unserialize(serialized_string)
Please see README.txt for more information.
"""

class PHPUnserialize(object):
"""
Class to unserialize something from the PHP Serialize format.
Usage:
u = PHPUnserialize()
data = u.unserialize(serialized_string)
"""

def __init__(self):
pass

def session_decode(self, data):
"""Thanks to Ken Restivo for suggesting the addition
of session_encode
"""
session = {}
while len(data) > 0:
(offset, key) = self.read_until(data, 0, '|')
if offset > 0:
(dtype, dataoffset, value) = self._unserialize(data, offset+1)
data = data[offset+1+dataoffset:]
session[key] = value
else:
return session

return session

def unserialize(self, data):
return self._unserialize(data, 0)[2]

def _unserialize(self, data, offset=0):
"""
Find the next token and unserialize it.
Recurse on array.
offset = raw offset from start of data
return (type, offset, value)
"""

buf = []
dtype = string.lower(data[offset:offset+1])

#print "# dtype =", dtype

# 't:' = 2 chars
dataoffset = offset + 2
typeconvert = lambda x : x
chars = datalength = 0

# int => Integer
if dtype == 'i':
typeconvert = lambda x : int(x)
(chars, readdata) = self.read_until(data, dataoffset, ';')
# +1 for end semicolon
dataoffset += chars + 1

# bool => Boolean
elif dtype == 'b':
typeconvert = lambda x : (int(x) == 1)
(chars, readdata) = self.read_until(data, dataoffset, ';')
# +1 for end semicolon
dataoffset += chars + 1

# double => Floating Point
elif dtype == 'd':
typeconvert = lambda x : float(x)
(chars, readdata) = self.read_until(data, dataoffset, ';')
# +1 for end semicolon
dataoffset += chars + 1

# n => None
elif dtype == 'n':
readdata = None

# s => String
elif dtype == 's':
(chars, stringlength) = self.read_until(data, dataoffset, ':')
# +2 for colons around length field
dataoffset += chars + 2

# +1 for start quote
(chars, readdata) = self.read_chars(data, dataoffset+1, int(stringlength))
# +2 for endquote semicolon
dataoffset += chars + 2

if chars != int(stringlength) != int(readdata):
raise Exception("String length mismatch")

# array => Dict
# If you originally serialized a Tuple or List, it will
# be unserialized as a Dict. PHP doesn't have tuples or lists,
# only arrays - so everything has to get converted into an array
# when serializing and the original type of the array is lost
elif dtype == 'a':
readdata = {}

# How many keys does this list have?
(chars, keys) = self.read_until(data, dataoffset, ':')
# +2 for colons around length field
dataoffset += chars + 2

# Loop through and fetch this number of key/value pairs
for i in range(0, int(keys)):
# Read the key
(ktype, kchars, key) = self._unserialize(data, dataoffset)
dataoffset += kchars
#print "Key(%i) = (%s, %i, %s) %i" % (i, ktype, kchars, key, dataoffset)

# Read value of the key
(vtype, vchars, value) = self._unserialize(data, dataoffset)
dataoffset += vchars
#print "Value(%i) = (%s, %i, %s) %i" % (i, vtype, vchars, value, dataoffset)

# Set the list element
readdata[key] = value

# +1 for end semicolon
dataoffset += 1
#chars = int(dataoffset) - start

# I don't know how to unserialize this
else:
raise Exception("Unknown / Unhandled data type (%s)!" % dtype)


return (dtype, dataoffset-offset, typeconvert(readdata))

def read_until(self, data, offset, stopchar):
"""
Read from data[offset] until you encounter some char 'stopchar'.
"""
buf = []
char = data[offset:offset+1]
i = 2
while char != stopchar:
# Consumed all the characters and havent found ';'
if i+offset > len(data):
raise Exception("Invalid")
buf.append(char)
char = data[offset+(i-1):offset+i]
i += 1

# (chars_read, data)
return (len(buf), "".join(buf))

def read_chars(self, data, offset, length):
"""
Read 'length' number of chars from data[offset].
"""
buf = []
# Account for the starting quote char
#offset += 1
for i in range(0, length):
char = data[offset+(i-1):offset+i]
buf.append(char)

# (chars_read, data)
return (len(buf), "".join(buf))


18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
usage:

python session_inspector.py

Commands:
isauth session_id1 session_id2 session_id3

returns 0 or 1 if the user of that session id is authenticated
each line of the response corresponds to one of the key passed
the lines are ended by \r\n

quit
closes the connection to the server

>telnet localhost 3002
isauth session_id
isauth session_ida session_idb session_idc
quit
Empty file added __init__.py
Empty file.
14 changes: 14 additions & 0 deletions conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
INSPECTOR_INTERFACE='0.0.0.0'
INSPECTOR_PORT=3002

# if you have several servers with different weigths, then try something like:
# sessServers = (['127.0.0.1:11211'] * 3) + (['127.0.0.1:11212'] * 5)
# where 3 and 5 are the weigths defined for those servers in Memcache::addServer in PHP
sessServers = ['127.0.0.1:11211']

#memcache key prefix, use '' if none set.
prefix = ''

# key inside the session array that stores if the user is authenticated or not
# for example this is what symfony uses
auth_key = 'symfony/user/sfUser/authenticated'
65 changes: 65 additions & 0 deletions session_inspector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.error import ConnectionDone
from twisted.protocols.basic import LineOnlyReceiver
import memcache
import sys
from PHPUnserialize import *
from conf import *

mc = memcache.Client(sessServers, debug=0)

class InspectorReceiver(LineOnlyReceiver):
delimiter = '\r\n'

def connectionMade(self):
self.peer = self.transport.getPeer()
self.peerAddr = "%s:%d" % (self.peer.host, self.peer.port)
print("%s connection with %s established" % (self.__class__.__name__, self.peerAddr))

def connectionLost(self, reason):
if reason.check(ConnectionDone):
print("%s connection with %s closed cleanly" % (self.__class__.__name__, self.peerAddr))
else:
print("%s connection with %s lost: %s" % (self.__class__.__name__, self.peerAddr, reason.value))

def isAuth(self, is_auth):
self.transport.write("%d\r\n" % (is_auth, ))

def lineReceived(self, line):
global mc, prefix, auth_key

try:
values = line.strip().split()

if len(values) < 1:
pass

if values[0] == 'isauth' and len(values) > 1:
for key in values[1:]:
data = mc.get(prefix + key)
if not data:
self.isAuth(False)
else:
try:
session = PHPUnserialize().session_decode(data)
self.isAuth(session[auth_key])
except:
self.isAuth(False)

elif values[0] == 'quit':
self.transport.loseConnection()
else:
raise Exception('Invalid command')
except:
print('invalid line received from client %s' % self.peerAddr)
return

def startListener(interface, port, protocol):
factory = Factory()
factory.protocol = protocol
return reactor.listenTCP( int(port), factory, interface=interface )

startListener(INSPECTOR_INTERFACE, INSPECTOR_PORT, InspectorReceiver)

reactor.run()

0 comments on commit fc96564

Please sign in to comment.