Commit 505a61ac authored by Jim Fulton's avatar Jim Fulton

Implemented new authorization model.

No longer use Realm module.
parent 9568a570
...@@ -102,9 +102,9 @@ Published objects ...@@ -102,9 +102,9 @@ Published objects
concatinating the sub-object name with the special attribute concatinating the sub-object name with the special attribute
name. For example, let 'foo.bar' be a dictionary, and foo.bar.spam name. For example, let 'foo.bar' be a dictionary, and foo.bar.spam
an item in the dictionary. When attempting to obtain the special an item in the dictionary. When attempting to obtain the special
attribute '__realm__', the object publisher will first try to attribute '__roles__', the object publisher will first try to
evaluate 'foo.bar.spam.__realm__', and then try to evaluate: evaluate 'foo.bar.spam.__roles__', and then try to evaluate:
'foo.bar["spam"+"__realm__"]'. 'foo.bar["spam"+"__roles__"]'.
Access Control Access Control
...@@ -117,11 +117,7 @@ Access Control ...@@ -117,11 +117,7 @@ Access Control
a collection of named groups. Each group must be a dictionary that a collection of named groups. Each group must be a dictionary that
use names as keys (i.e. sets of names). The values in these use names as keys (i.e. sets of names). The values in these
dictionaries may contain passwords for authenticating each of the dictionaries may contain passwords for authenticating each of the
names. Alternatively, passwords may be provided in separate "realm" names. The basic authentication realm name used is
objects. If no realm is provided, then basic authentication will be
used and the object publisher will attempt to authenticate the
access to the object using one of the supplied name and password
pairs. The basic authentication realm name used is
'module_name.server_name', where 'module_name' is the name of the 'module_name.server_name', where 'module_name' is the name of the
module containing the published objects, and server_name is the name module containing the published objects, and server_name is the name
of the web server. of the web server.
...@@ -154,41 +150,23 @@ Access Control ...@@ -154,41 +150,23 @@ Access Control
set to None, in which case the object will be public, even if set to None, in which case the object will be public, even if
containing objects are not. containing objects are not.
Realms Roles
Realms provide a mechanism for separating authentication and Meaning of __roles__:
authorization.
An object may have an attribute '__realm__', which should be None -- Public
either a realm object, or a mapping object mapping names to False and not None -- private
passwords. A sequence of role names.
If a mapping object is provided, then it will be used for
basic authentication using a realm name of
"module_name.server_name", where "module_name" is the name of
the module containing the published objects, and server_name
is the name of the web server.
If a realm object is used, then it will use an application
supplied realm name and password mapping object, and may use
other than basic authentication. If a realm is provided that
does not include it's own name to password mapping, then the
name to password mappings contained in an object's
'__allow_groups__' attribute will be used.
An object may "acquir" a realm from one of it's parent
objects in the URI path to the object, including the module
used to publish the object.
Fixed-attribute objects Fixed-attribute objects
For some interesting objects, such as functions, and methods, For some interesting objects, such as functions, and methods,
it may not be possible for applications to set it may not be possible for applications to set
'__allow_groups__' or '__realm__' attributes. In these cases, the '__roles__' attributes. In these cases, the
object's parent object may contain attributes object's parent object may contain attribute
'object_name__allow_groups__' or 'object_name__realm__', which 'object_name__roles__', which
will be used as surrogates for the object's '__allow_groups__' will be used as surrogates for the object's
and '__realm__' attributes. '__role__' attribute.
Determining the authenticated user name Determining the authenticated user name
...@@ -479,18 +457,13 @@ Examples ...@@ -479,18 +457,13 @@ Examples
# web_objects={'greet':hi, 'addxy':add} # web_objects={'greet':hi, 'addxy':add}
# Here's out "password" database.
from Realm import Realm
__realm__=Realm('spam.digicool.com',
{'jim':'spam', 'paul':'eggs'})
Publishing a module using CGI Publishing a module using CGI
o Do not copy the module to be published to the cgi-bin o Do not copy the module to be published to the cgi-bin
directory. directory.
o Copy the files: cgi_module_publisher.pyc and CGIResponse.pyc, o Copy the files: cgi_module_publisher.pyc and CGIResponse.pyc,
Realm.pyc, and newcgi.pyc, to the directory containing the and newcgi.pyc, to the directory containing the
module to be published, or to a directory in the standard module to be published, or to a directory in the standard
(compiled in) Python search path. (compiled in) Python search path.
...@@ -504,7 +477,7 @@ Publishing a module using CGI ...@@ -504,7 +477,7 @@ Publishing a module using CGI
Publishing a module using Fast CGI Publishing a module using Fast CGI
o Copy the files: cgi_module_publisher.pyc and CGIResponse.pyc, o Copy the files: cgi_module_publisher.pyc and CGIResponse.pyc,
Realm.pyc, and newcgi.pyc, to the directory containing the and newcgi.pyc, to the directory containing the
module to be published, or to a directory in the standard module to be published, or to a directory in the standard
(compiled in) Python search path. (compiled in) Python search path.
...@@ -518,7 +491,7 @@ Publishing a module using Fast CGI ...@@ -518,7 +491,7 @@ Publishing a module using Fast CGI
o Configure the Fast CGI-enabled web server to execute this o Configure the Fast CGI-enabled web server to execute this
file. file.
$Id: Publish.py,v 1.46 1997/07/28 22:01:58 jim Exp $""" $Id: Publish.py,v 1.47 1997/09/02 21:18:53 jim Exp $"""
#' #'
# Copyright # Copyright
# #
...@@ -572,7 +545,8 @@ $Id: Publish.py,v 1.46 1997/07/28 22:01:58 jim Exp $""" ...@@ -572,7 +545,8 @@ $Id: Publish.py,v 1.46 1997/07/28 22:01:58 jim Exp $"""
# #
# See end of file for change log. # See end of file for change log.
# #
__version__='$Revision: 1.46 $'[11:-2] ##########################################################################
__version__='$Revision: 1.47 $'[11:-2]
def main(): def main():
...@@ -582,12 +556,13 @@ def main(): ...@@ -582,12 +556,13 @@ def main():
if __name__ == "__main__": main() if __name__ == "__main__": main()
import sys, os, string, types, cgi, regex, regsub import sys, os, string, types, cgi, regex, regsub, base64
from string import *
from CGIResponse import Response from CGIResponse import Response
from Realm import Realm, allow_group_composition
from urllib import quote from urllib import quote
from cgi import FieldStorage, MiniFieldStorage from cgi import FieldStorage, MiniFieldStorage
from string import upper, lower, strip
UNSPECIFIED_ROLES=''
try: try:
from ExtensionClass import Base from ExtensionClass import Base
...@@ -606,6 +581,93 @@ except: ...@@ -606,6 +581,93 @@ except:
class ModulePublisher: class ModulePublisher:
def __init__(self,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
environ=os.environ):
self.environ=environ
fp=None
try:
if environ['REQUEST_METHOD'] != 'GET': fp=stdin
except: pass
try:
self.HTTP_AUTHORIZATION=environ['HTTP_AUTHORIZATION']
del environ['HTTP_AUTHORIZATION']
except:
try:
self.HTTP_AUTHORIZATION=environ['HTTP_CGI_AUTHORIZATION']
del environ['HTTP_CGI_AUTHORIZATION']
except: pass
form={}
if environ.has_key('HTTP_COOKIE'):
parse_cookie(self.environ['HTTP_COOKIE'], form)
fs=FieldStorage(fp=fp,environ=environ,keep_blank_values=1)
try: fslist=fs.list
except: fslist=None
if fslist is None: form={'BODY':fs}
else:
tuple_items={}
type_re=regex.compile('\(:\|%3[aA]\)\([a-zA-Z][a-zA-Z0-9_]+\)')
type_search=type_re.search
lt=type([])
CGI_name=isCGI_NAME
for item in fslist:
key=item.name
try:
if (item.file and
(item.filename is not None or
'content-type' in map(lower,
item.headers.keys()))):
item=FileUpload(item)
else:
item=item.value
except: pass
seqf=None
l=type_search(key)
while l >= 0:
type_name=type_re.group(2)
key=key[:l]+key[l+len(type_re.group(0)):]
if type_name == 'list':
seqf=list
elif type_name == 'tuple':
seqf=tuple
tuple_items[key]=1
else:
item=type_converters[type_name](item)
l=type_search(key)
# Filter out special names from form:
if CGI_name(key) or key[:5]=='HTTP_': continue
try:
found=form[key]
if type(found) is lt: found.append(item)
else:
found=[found,item]
form[key]=found
except:
if seqf: item=[item]
form[key]=item
for key in tuple_items.keys(): form[key]=tuple(form[key])
request=self.request=Request(environ,form,stdin)
self.response=Response(stdout=stdout, stderr=stderr)
self.stdin=stdin
self.stdout=stdout
self.stderr=stderr
self.base=request.base
self.script=request.script
def html(self,title,body): def html(self,title,body):
return ("<html>\n" return ("<html>\n"
"<head>\n<title>%s</title>\n</head>\n" "<head>\n<title>%s</title>\n</head>\n"
...@@ -633,44 +695,20 @@ class ModulePublisher: ...@@ -633,44 +695,20 @@ class ModulePublisher:
"<!--%s-->" "<!--%s-->"
% (name,self.request)) % (name,self.request))
def unauthorized(self, realm):
self.response['WWW-authenticate']='basic realm="%s"' % realm
raise 'Unauthorized', (
"""<strong>You are not authorized to access this resource.
</strong>
"""
)
def forbiddenError(self,object=None): def forbiddenError(self,object=None):
raise 'NotFound',self.html( raise 'NotFound',self.html(
"Resource not found", "Resource not found",
"Sorry, the requested document does not exist.\n" "Sorry, the requested document does not exist.\n"
"<!--%s-->" % object) "<!--%s-->" % object)
def env(self,key):
try: return self.environ[key]
except:
if key == 'HTTP_AUTHORIZATION':
try:
return self.environ['HTTP_CGI_AUTHORIZATION']
except:
return ''
return ''
def validate(self,groups,realm=None):
sys.stdout=self.stdout
if not realm:
try: realm=self.realm
except:
realm=Realm("%s.%s" %
(self.module_name,self.request.SERVER_NAME))
self.realm=realm
try:
user=realm.validate(self.env("HTTP_AUTHORIZATION"),groups)
self.request['AUTHENTICATED_USER']=user
get_transaction().note("%s\t%s" % (user,self.env('PATH_INFO')))
return user
except realm.Unauthorized, v:
auth,v=v
self.response['WWW-authenticate']=auth
raise 'Unauthorized', v
except:
self.forbiddenError()
def get_request_data(self,request_params): def get_request_data(self,request_params):
try: request_params=request_params() try: request_params=request_params()
except: pass except: pass
...@@ -680,7 +718,7 @@ class ModulePublisher: ...@@ -680,7 +718,7 @@ class ModulePublisher:
def get_module_info(self, server_name, module_name, module): def get_module_info(self, server_name, module_name, module):
realm_name="%s.%s" % (module_name,server_name) realm="%s.%s" % (module_name,server_name)
try: bobo_before=module.__bobo_before__ try: bobo_before=module.__bobo_before__
except: bobo_before=None except: bobo_before=None
...@@ -688,14 +726,6 @@ class ModulePublisher: ...@@ -688,14 +726,6 @@ class ModulePublisher:
try: bobo_after=module.__bobo_after__ try: bobo_after=module.__bobo_after__
except: bobo_after=None except: bobo_after=None
# Try to get realm from module
try:
realm=module.__realm__
if type(realm) is type(''):
realm_name=realm
realm=None
except: realm=None
# Get request data from outermost environment: # Get request data from outermost environment:
try: request_params=module.__request_data__ try: request_params=module.__request_data__
except: request_params=None except: request_params=None
...@@ -708,14 +738,14 @@ class ModulePublisher: ...@@ -708,14 +738,14 @@ class ModulePublisher:
except: groups=None except: groups=None
web_objects=None web_objects=None
find_object=old_find_object
try: try:
object=module.bobo_application object=module.bobo_application
find_object=new_find_object
try: try:
groups=object.__allow_groups__ groups=object.__allow_groups__
inherited_groups.append(groups) inherited_groups.append(groups)
except: groups=None except: groups=None
try: roles=object.__roles__
except: roles=UNSPECIFIED_ROLES
except: except:
try: try:
web_objects=module.web_objects web_objects=module.web_objects
...@@ -728,9 +758,9 @@ class ModulePublisher: ...@@ -728,9 +758,9 @@ class ModulePublisher:
if web_objects is not None: doc=' ' if web_objects is not None: doc=' '
else: doc=None else: doc=None
return (bobo_before, bobo_after, realm, realm_name, request_params, return (bobo_before, bobo_after, request_params,
inherited_groups, groups, inherited_groups, groups, roles,
object, doc, published, find_object) object, doc, published, realm)
def publish(self, module_name, after_list, published='web_objects', def publish(self, module_name, after_list, published='web_objects',
...@@ -739,7 +769,7 @@ class ModulePublisher: ...@@ -739,7 +769,7 @@ class ModulePublisher:
# First check for "cancel" redirect: # First check for "cancel" redirect:
cancel='' cancel=''
try: try:
if string.lower(self.request['SUBMIT'])=='cancel': if lower(self.request['SUBMIT'])=='cancel':
cancel=self.request['CANCEL_ACTION'] cancel=self.request['CANCEL_ACTION']
except: pass except: pass
if cancel: if cancel:
...@@ -747,13 +777,14 @@ class ModulePublisher: ...@@ -747,13 +777,14 @@ class ModulePublisher:
if module_name[-4:]=='.cgi': module_name=module_name[:-4] if module_name[-4:]=='.cgi': module_name=module_name[:-4]
self.module_name=module_name self.module_name=module_name
request=self.request
response=self.response response=self.response
server_name=self.request.SERVER_NAME server_name=request.SERVER_NAME
try: try:
(bobo_before, bobo_after, realm, realm_name, request_params, (bobo_before, bobo_after, request_params,
inherited_groups, groups, inherited_groups, groups, roles,
object, doc, published, find_object object, doc, published, realm
) = info = module_dicts[server_name, module_name] ) = info = module_dicts[server_name, module_name]
except: except:
info={} info={}
...@@ -762,16 +793,13 @@ class ModulePublisher: ...@@ -762,16 +793,13 @@ class ModulePublisher:
info=self.get_module_info(server_name, module_name, info=self.get_module_info(server_name, module_name,
info[module_name]) info[module_name])
module_dicts[server_name, module_name]=info module_dicts[server_name, module_name]=info
(bobo_before, bobo_after, realm, realm_name, request_params, (bobo_before, bobo_after, request_params,
inherited_groups, groups, inherited_groups, groups, roles,
object, doc, published, find_object object, doc, published, realm
) = info ) = info
except: raise ImportError, ( except: raise ImportError, (
sys.exc_type, sys.exc_value, sys.exc_traceback) sys.exc_type, sys.exc_value, sys.exc_traceback)
if find_object is old_find_object: response.setBase(self.base,'')
after_list[0]=bobo_after after_list[0]=bobo_after
if bobo_before is not None: bobo_before(); if bobo_before is not None: bobo_before();
...@@ -779,13 +807,13 @@ class ModulePublisher: ...@@ -779,13 +807,13 @@ class ModulePublisher:
if request_params: self.get_request_data(request_params) if request_params: self.get_request_data(request_params)
# Get a nice clean path list: # Get a nice clean path list:
path=(string.strip(self.env('PATH_INFO'))) path=strip(request['PATH_INFO'])
if path[:1]=='/': path=path[1:] if path[:1]=='/': path=path[1:]
if path[-1:]=='/': path=path[:-1] if path[-1:]=='/': path=path[:-1]
path=string.splitfields(path,'/') path=split(path,'/')
while path and not path[0]: path = path[1:] while path and not path[0]: path = path[1:]
method=upper(self.request['REQUEST_METHOD']) method=upper(request['REQUEST_METHOD'])
if method=='GET' or method=='POST': method='index_html' if method=='GET' or method=='POST': method='index_html'
# Get default object if no path was specified: # Get default object if no path was specified:
...@@ -803,56 +831,124 @@ class ModulePublisher: ...@@ -803,56 +831,124 @@ class ModulePublisher:
if not path: path = ['help'] if not path: path = ['help']
# Traverse the URL to find the object: # Traverse the URL to find the object:
(object, parents, URL, groups, realm, inherited_groups, URL=self.script
realm_name,roles) = find_object(self, info, path, method) parents=[]
# Do authorization checks try: # Try to bind the top-level object to the request
if groups is not None: object=object.__of__(RequestContainer(REQUEST=self.request))
except: pass
# Do composition, if we've got a named group: while path:
try: entry_name,path=path[0], path[1:]
try: groups.keys # See if we've got a mapping URL="%s/%s" % (URL,quote(entry_name))
except: got=0
groups=groups() if entry_name:
groups.keys if entry_name[:1]=='_': self.forbiddenError(entry_name)
g={None:None} try: traverse=object.__bobo_traverse__
for i in inherited_groups[:-1]: except: traverse=None
g=allow_group_composition(g,i) if traverse is not None:
if roles: request['URL']=URL
groups=allow_group_composition(g,inherited_groups[-1]) subobject=traverse(request,entry_name)
if type(roles) is type(''):
groups=(g[roles],)
else:
groups=map(lambda role: g[role], roles)
else: else:
groups=allow_group_composition(groups,g) try:
subobject=getattr(object,entry_name)
except AttributeError:
try:
subobject=object[entry_name]
got=1
except: except:
# groups was not a mapping (or a function returning a self.notFoundError("%s" % (entry_name))
# mapping), so no point in composing.
pass
if groups is not None:
if not groups: self.forbiddenError()
try: try:
if realm.name is None: try: doc=subobject.__doc__
realm.name=realm_name except: doc=getattr(subobject, entry_name+'__doc__')
if not doc: raise AttributeError, entry_name
except: self.notFoundError("%s" % (entry_name))
try: roles=subobject.__roles__
except: except:
try: if not got:
len(realm) try: roles=getattr(object,entry_name+'__roles__')
realm=Realm(realm_name,realm) except:
if (entry_name=='manage' or
entry_name[:7]=='manage_'):
roles='manage',
# Promote subobject to object
parents.append(object)
object=subobject
# Check for method:
if (not path and hasattr(object,method) and
entry_name != method):
response.setBase(URL+'/','')
path=[method]
if entry_name != method and method != 'index_html':
self.notFoundError(method)
parents.append(object)
parents.reverse()
# Do authorization checks
user=None
if roles is not None:
last_parent_index=len(parents)
for i in range(last_parent_index):
try: groups=parents[i].__allow_groups__
except: groups=-1
if groups == -1: continue
try: v=groups.validate
except: v=old_validation
if v is old_validation and roles is UNSPECIFIED_ROLES:
# No roles, so if we have a named group, get roles from
# group keys
try: roles=groups.keys()
except AttributeError:
try: groups=groups()
except: pass
try: roles=groups.keys()
except: pass except: pass
self.validate(groups,realm)
if groups is None: break # Public group
try: auth=self.HTTP_AUTHORIZATION
except: self.unauthorized(realm)
if v is old_validation:
user=old_validation(groups, auth, roles)
elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
else: user=v(request, auth, roles)
while user is None and i < last_parent_index:
try: groups=parents[i].__allow_groups__
except: groups=-1
i=i+1
if groups == -1: continue
try: v=groups.validate
except: v=old_validation
if v is old_validation:
user=old_validation(groups, auth, roles)
elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
else: user=v(request, auth, roles)
if user is None: self.unauthorized(realm)
break
if user is not None: request['AUTHENTICATED_USER']=user
del parents[0]
# Attempt to start a transaction: # Attempt to start a transaction:
try: transaction=get_transaction() try: transaction=get_transaction()
except: transaction=None except: transaction=None
if transaction is not None: if transaction is not None:
info="\t" + self.env('PATH_INFO') info="\t" + request['PATH_INFO']
try: try:
u=self.request['AUTHENTICATED_USER'] u=request['AUTHENTICATED_USER']
try: u="%s.%s" % (u, self.request['session__domain'])
except: pass
try: info=u+info try: info=u+info
except: pass except: pass
except: pass except: pass
...@@ -885,26 +981,24 @@ class ModulePublisher: ...@@ -885,26 +981,24 @@ class ModulePublisher:
except: except:
return response.setBody(object) return response.setBody(object)
query=self.request request['RESPONSE']=response
query['RESPONSE']=response request['URL']=URL
query['URL']=URL request['PARENT_URL']=URL[:rfind(URL,'/')]
query['PARENT_URL']=URL[:string.rfind(URL,'/')]
if parents: if parents:
parents.reverse()
selfarg=parents[0] selfarg=parents[0]
for i in range(len(parents)): for i in range(len(parents)):
try: try:
p=parents[i].aq_self p=parents[i].aq_self
parents[i]=p parents[i]=p
except: pass except: pass
query['PARENTS']=parents request['PARENTS']=parents
args=[] args=[]
nrequired=len(argument_names) - (len(defaults or [])) nrequired=len(argument_names) - (len(defaults or []))
for name_index in range(len(argument_names)): for name_index in range(len(argument_names)):
argument_name=argument_names[name_index] argument_name=argument_names[name_index]
try: try:
v=query[argument_name] v=request[argument_name]
args.append(v) args.append(v)
except (KeyError,AttributeError,IndexError): except (KeyError,AttributeError,IndexError):
if argument_name=='self': args.append(selfarg) if argument_name=='self': args.append(selfarg)
...@@ -944,255 +1038,6 @@ def str_field(v): ...@@ -944,255 +1038,6 @@ def str_field(v):
except: pass except: pass
return v return v
def attr_meta_data(object, subobject, entry_name,
inherited_groups, groups,
realm, realm_name, default_realm_name, roles):
try:
groups=subobject.__allow_groups__
inherited_groups.append(groups)
except:
try:
groups=getattr(object, entry_name+'__allow_groups__')
inherited_groups.append(groups)
except: pass
try: roles=subobject.__roles__
except:
try: roles=getattr(object,entry_name+'__roles__')
except: pass
try: doc=subobject.__doc__
except:
try: doc=getattr(object,entry_name+'__doc__')
except: doc=None
try:
realm=subobject.__realm__
realm_name=default_realm_name
except:
try:
realm=getattr(object,entry_name+'__realm__')
realm_name=default_realm_name
except: pass
return inherited_groups, groups, realm, realm_name, doc, roles
def item_meta_data(subobject,
inherited_groups, groups,
realm, realm_name, default_realm_name, roles):
try:
groups=subobject.__allow_groups__
inherited_groups.append(groups)
except: pass
try: doc=subobject.__doc__
except: doc=None
try: roles=subobject.__roles__
except: roles=None
try:
realm=subobject.__realm__
realm_name=default_realm_name
except: pass
return inherited_groups, groups, realm, realm_name, doc, roles
def new_find_object(self, info, path, method):
(bobo_before, bobo_after, realm, realm_name, request_params,
inherited_groups, groups,
object, doc, published, ignore) = info
default_realm_name=realm_name
inherited_groups=inherited_groups[:]
request=self.request
URL=self.script
parents=[]
try: # Try to bind the top-level object to the request
object=object.__of__(RequestContainer(
REQUEST=self.request, RESPONSE=self.response))
except: pass
roles=()
while path:
entry_name,path=path[0], path[1:]
URL="%s/%s" % (URL,quote(entry_name))
default_realm_name="%s.%s" % (entry_name,default_realm_name)
if entry_name:
try: traverse=object.__bobo_traverse__
except: traverse=None
if traverse is not None:
request['URL']=URL
subobject=traverse(request,entry_name)
(inherited_groups, groups,
realm, realm_name, doc, roles) = attr_meta_data(
object, subobject, entry_name,
inherited_groups, groups,
realm, realm_name, default_realm_name, roles)
else:
try:
subobject=getattr(object,entry_name)
(inherited_groups, groups,
realm, realm_name, doc, roles) = attr_meta_data(
object, subobject, entry_name,
inherited_groups, groups,
realm, realm_name, default_realm_name, roles)
except AttributeError:
try:
subobject=object[entry_name]
(inherited_groups, groups,
realm, realm_name, doc, roles) = item_meta_data(
subobject,
inherited_groups, groups,
realm, realm_name, default_realm_name, roles)
except (TypeError,AttributeError,KeyError), mess:
if not path and entry_name=='help' and doc:
object=doc
entry_name, subobject = (
'__doc__', self.html
('Documentation for ' +
((self.env('PATH_INFO') or
('/'+self.module_name))[1:]),
'<pre>\n%s\n</pre>' % doc)
)
else:
self.notFoundError("%s: %s" % (entry_name,mess))
# Perform simple checks
if (entry_name != '__doc__' and
(not doc or entry_name[0]=='_')
):
if not doc: entry_name=str(subobject)
self.forbiddenError(entry_name)
# Promote subobject to object
parents.append(object)
object=subobject
# Check for method:
if (not path and hasattr(object,method) and
entry_name != method):
path=[method]
if entry_name != method and method != 'index_html':
self.notFoundError(method)
return (object, parents, URL, groups, realm, inherited_groups,
realm_name, roles)
def old_find_object(self, info, path, method):
(bobo_before, bobo_after, realm, realm_name, request_params,
inherited_groups, groups,
object, doc, published, ignore) = info
default_realm_name=realm_name
inherited_groups=inherited_groups[:]
URL=self.script
parents=[]
# sad_pathetic_persistence_hack:
try: setstate=object.__dict__['_p_setstate']
except: setstate=None
if setstate: setstate(object)
topobject=object
while path:
if object is not topobject and topobject is not None:
topobject=None
try: # Try to bind the top-level object to the request
object=object.__of__(RequestContainer(
REQUEST=self.request, RESPONSE=self.response))
except: pass
entry_name,path=path[0], path[1:]
URL="%s/%s" % (URL,quote(entry_name))
default_realm_name="%s.%s" % (entry_name,default_realm_name)
if entry_name:
try:
subobject=getattr(object,entry_name)
# sad_pathetic_persistence_hack:
try: setstate=subobject.__dict__['_p_setstate']
except: setstate=None
if setstate: setstate(subobject)
(inherited_groups, groups,
realm, realm_name, doc) = attr_meta_data(
object, subobject, entry_name,
inherited_groups, groups,
realm, realm_name, default_realm_name)
try:
request_params=getattr(subobject,'__request_data__')
self.get_request_data(request_params)
except: pass
except AttributeError:
try:
subobject=object[entry_name]
# sad_pathetic_persistence_hack:
try: setstate=subobject.__dict__['_p_setstate']
except: setstate=None
if setstate: setstate(subobject)
(inherited_groups, groups,
realm, realm_name, doc) = item_meta_data(
subobject,
inherited_groups, groups,
realm, realm_name, default_realm_name)
try:
request_params=getattr(subobject,'__request_data__')
self.get_request_data(request_params)
except: pass
except (TypeError,AttributeError,KeyError), mess:
if not path and entry_name=='help' and doc:
object=doc
entry_name, subobject = (
'__doc__', self.html
('Documentation for ' +
((self.env('PATH_INFO') or
('/'+self.module_name))[1:]),
'<pre>\n%s\n</pre>' % doc)
)
else:
self.notFoundError("%s: %s" % (entry_name,mess))
if published:
# Bypass simple checks the first time
published=None
else:
# Perform simple checks
if (type(subobject)==types.ModuleType or
entry_name != '__doc__' and
(not doc or entry_name[0]=='_')
):
if not doc: entry_name=str(subobject)
self.forbiddenError(entry_name)
# Promote subobject to object
parents.append(object)
object=subobject
# Check for method:
if (not path and hasattr(object,method) and
entry_name != method):
path=[method]
if entry_name != method and method != 'index_html':
self.notFoundError(method)
return (object, parents, URL, groups, realm, inherited_groups,
realm_name, None)
class FileUpload: class FileUpload:
'''\ '''\
...@@ -1222,23 +1067,6 @@ class FileUpload: ...@@ -1222,23 +1067,6 @@ class FileUpload:
self.filename=aFieldStorage.filename self.filename=aFieldStorage.filename
def flatten_field(v,converter=None):
if type(v) is types.ListType:
if len(v) > 1: return map(flatten_field,v)
v=v[0]
try:
if v.file and (v.filename is not None or
'content-type' in map(string.lower,
v.headers.keys())):
v=FileUpload(v)
else:
v=v.value
except: pass
if converter: v=converter(v)
return v
def field2string(v): def field2string(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
...@@ -1253,28 +1081,28 @@ def field2text(v, nl=regex.compile('\r\n\|\n\r'), sub=regsub.gsub): ...@@ -1253,28 +1081,28 @@ def field2text(v, nl=regex.compile('\r\n\|\n\r'), sub=regsub.gsub):
def field2required(v): def field2required(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
if string.strip(v): return v if strip(v): return v
raise ValueError, 'No input for required field' raise ValueError, 'No input for required field'
def field2int(v): def field2int(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
# we can remove the check for an empty string when we go to python 1.4 # we can remove the check for an empty string when we go to python 1.4
if v: return string.atoi(v) if v: return atoi(v)
raise ValueError, 'Empty entry when integer expected' raise ValueError, 'Empty entry when integer expected'
def field2float(v): def field2float(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
# we can remove the check for an empty string when we go to python 1.4 # we can remove the check for an empty string when we go to python 1.4
if v: return string.atof(v) if v: return atof(v)
raise ValueError, 'Empty entry when floating-point number expected' raise ValueError, 'Empty entry when floating-point number expected'
def field2long(v): def field2long(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
# we can remove the check for an empty string when we go to python 1.4 # we can remove the check for an empty string when we go to python 1.4
if v: return string.atol(v) if v: return atol(v)
raise ValueError, 'Empty entry when integer expected' raise ValueError, 'Empty entry when integer expected'
def field2Regex(v): def field2Regex(v):
...@@ -1290,25 +1118,25 @@ def field2regex(v): ...@@ -1290,25 +1118,25 @@ def field2regex(v):
def field2Regexs(v): def field2Regexs(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
v= map(lambda v: regex.compile(v), string.split(v)) v= map(lambda v: regex.compile(v), split(v))
if v: return v if v: return v
def field2regexs(v): def field2regexs(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
v= map(lambda v: regex.compile(v, regex.casefold), string.split(v)) v= map(lambda v: regex.compile(v, regex.casefold), split(v))
if v: return v if v: return v
def field2tokens(v): def field2tokens(v):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
return string.split(v) return split(v)
def field2lines(v, crlf=regex.compile('\r\n\|\n\r')): def field2lines(v, crlf=regex.compile('\r\n\|\n\r')):
try: v=v.read() try: v=v.read()
except: v=str(v) except: v=str(v)
v=regsub.gsub(crlf,'\n',v) v=regsub.gsub(crlf,'\n',v)
return string.split(v,'\n') return split(v,'\n')
def field2date(v): def field2date(v):
from DateTime import DateTime from DateTime import DateTime
...@@ -1395,34 +1223,26 @@ class Request: ...@@ -1395,34 +1223,26 @@ class Request:
""" """
def __init__(self,environ,form,stdin): def __init__(self,environ,form,stdin):
try: environ['HTTP_AUTHORIZATION']= \
environ['HTTP_CGI_AUTHORIZATION']
except: pass
self.environ=environ self.environ=environ
self.form=form self.other=form
self.stdin=stdin self.stdin=stdin
self.other={}
def env(key,d=environ): b=script=strip(environ['SCRIPT_NAME'])
try: return d[key]
except: return ''
b=script=string.strip(environ['SCRIPT_NAME'])
while b and b[-1]=='/': b=b[:-1] while b and b[-1]=='/': b=b[:-1]
p = string.rfind(b,'/') p = rfind(b,'/')
if p >= 0: b=b[:p+1] if p >= 0: b=b[:p+1]
else: b='' else: b=''
while b and b[0]=='/': b=b[1:] while b and b[0]=='/': b=b[1:]
try: try:
try: try:
server_url="http://%s" % string.strip(environ['HTTP_HOST']) server_url="http://%s" % strip(environ['HTTP_HOST'])
except: except:
server_url=string.strip(environ['SERVER_URL']) server_url=strip(environ['SERVER_URL'])
if server_url[-1:]=='/': server_url=server_url[:-1] if server_url[-1:]=='/': server_url=server_url[:-1]
except: except:
server_port=env('SERVER_PORT') server_port=environ['SERVER_PORT']
server_url=('http://'+ server_url=('http://'+
string.strip(environ['SERVER_NAME']) + strip(environ['SERVER_NAME']) +
(server_port and ':'+server_port) (server_port and ':'+server_port)
) )
...@@ -1439,23 +1259,20 @@ class Request: ...@@ -1439,23 +1259,20 @@ class Request:
self.other[key]=value self.other[key]=value
__http_colon=regex.compile("\(:\|\(%3[aA]\)\)")
def __str__(self): def __str__(self):
def str(self,name): def str(self,name):
dict=getattr(self,name) dict=getattr(self,name)
return "%s:\n\t%s\n\n" % ( return "%s:\n\t%s\n\n" % (
name, name,
string.joinfields( join(
map(lambda k, d=dict: "%s: %s" % (k, d[k]), dict.keys()), map(lambda k, d=dict: "%s: %s" % (k, d[k]), dict.keys()),
"\n\t" "\n\t"
) )
) )
return "%s\n%s\n%s\n%s" % ( return "%s\n%s\n%s" % (
str(self,'other'),str(self,'form'),str(self,'environ'), str(self,'other'),str(self,'environ'),
str(self,'cookies')) str(self,'cookies'))
__repr__=__str__ __repr__=__str__
...@@ -1466,7 +1283,10 @@ class Request: ...@@ -1466,7 +1283,10 @@ class Request:
return 1 return 1
except: return 0 except: return 0
def __getitem__(self,key): def __getitem__(self,key,
URLmatch=regex.compile('URL[0-9]$').match,
BASEmatch=regex.compile('BASE[0-9]$').match,
):
"""Get a variable value """Get a variable value
Return a value for the required variable name. Return a value for the required variable name.
...@@ -1480,60 +1300,28 @@ class Request: ...@@ -1480,60 +1300,28 @@ class Request:
try: return other[key] try: return other[key]
except: pass except: pass
if self.special_names.has_key(key) or key[:5] == 'HTTP_': if URLmatch(key) >= 0 and other.has_key('URL'):
n=ord(key[3])-ord('0')
URL=other['URL']
for i in range(0,n):
l=rfind(URL,'/')
if l >= 0: URL=URL[:l]
else: raise KeyError, key
other[key]=URL
return URL
if isCGI_NAME(key) or key[:5] == 'HTTP_':
try: return self.environ[key] try: return self.environ[key]
except: return '' except: return ''
if key=='REQUEST': return self if key=='REQUEST': return self
if key!='cookies': if BASEmatch(key) >= 0 and other.has_key('URL'):
try:
converter=None
try:
v=self.form[key]
except:
# Hm, maybe someone used a form with a name like: name:type
try: tf=self.__dict__['___typed_form']
except:
tf=self.__dict__['___typed_form']={}
form=self.form
colon=self.__http_colon
search=colon.search
group=colon.group
for k in form.keys():
l = search(k)
if l > 0:
tf[k[:l]]=form[k],k[l+len(group(1)):]
v,t=tf[key]
try: converter=type_converters[t]
except: pass
v=flatten_field(v,converter)
other[key]=v
return v
except (KeyError,AttributeError,IndexError): pass
if not self.__dict__.has_key('cookies'):
if self.environ.has_key('HTTP_COOKIE'):
cookies=parse_cookie(self.environ['HTTP_COOKIE'])
else: cookies={}
self.cookies=cookies
if key=='cookies': return self.cookies
try:
r=self.cookies[key]
other[key]=r
return r
except: pass
try:
if regex.match('BASE[0-9]$',key) >= 0:
n=ord(key[4])-ord('0') n=ord(key[4])-ord('0')
URL=self['URL'] URL=other['URL']
baselen=len(self.base) baselen=len(self.base)
for i in range(0,n): for i in range(0,n):
baselen=string.find(URL,'/',baselen+1) baselen=find(URL,'/',baselen+1)
if baselen < 0: if baselen < 0:
baselen=len(URL) baselen=len(URL)
break break
...@@ -1541,23 +1329,13 @@ class Request: ...@@ -1541,23 +1329,13 @@ class Request:
if base[-1:]=='/': base=base[:-1] if base[-1:]=='/': base=base[:-1]
other[key]=base other[key]=base
return base return base
if regex.match('URL[0-9]$',key) >= 0:
n=ord(key[3])-ord('0')
URL=self['URL']
if URL[-1:]=='/': URL=URL[:-1]
for i in range(0,n):
l=string.rfind(URL,'/')
if l >= 0: URL=URL[:l]
else: raise KeyError, key
other[key]=URL
return URL
except: pass
raise KeyError, key raise KeyError, key
__getattr__=__getitem__ __getattr__=__getitem__
special_names = {
isCGI_NAME = {
'SERVER_SOFTWARE' : 1, 'SERVER_SOFTWARE' : 1,
'SERVER_NAME' : 1, 'SERVER_NAME' : 1,
'GATEWAY_INTERFACE' : 1, 'GATEWAY_INTERFACE' : 1,
...@@ -1575,7 +1353,8 @@ class Request: ...@@ -1575,7 +1353,8 @@ class Request:
'REMOTE_IDENT' : 1, 'REMOTE_IDENT' : 1,
'CONTENT_TYPE' : 1, 'CONTENT_TYPE' : 1,
'CONTENT_LENGTH' : 1, 'CONTENT_LENGTH' : 1,
} }.has_key
def parse_cookie(text, def parse_cookie(text,
...@@ -1610,44 +1389,42 @@ def parse_cookie(text, ...@@ -1610,44 +1389,42 @@ def parse_cookie(text,
return apply(parse_cookie,(text[l:],result)) return apply(parse_cookie,(text[l:],result))
def old_validation(groups, HTTP_AUTHORIZATION, roles=UNSPECIFIED_ROLES):
if lower(HTTP_AUTHORIZATION[:6]) != 'basic ': return None
[name,password] = string.splitfields(
base64.decodestring(
split(HTTP_AUTHORIZATION)[-1]), ':')
if roles is None: return name
class CGIModulePublisher(ModulePublisher): keys=None
def __init__(self,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
environ=os.environ):
self.environ=environ
fp=None
try: try:
if environ['REQUEST_METHOD'] != 'GET': fp=stdin keys=groups.keys
except:
try:
groups=groups() # Maybe it was a method defining a group
keys=groups.keys
except: pass except: pass
fs=FieldStorage(fp=fp,environ=environ,keep_blank_values=1) if keys is not None:
try: list=fs.list # OK, we have a named group, so apply the roles to the named
except: list=None # group.
if list is None: form={'BODY':fs} if roles is UNSPECIFIED_ROLES: roles=keys()
else: g=[]
form={} for role in roles:
lt=type([]) if groups.has_key(role): g.append(groups[role])
for item in list: groups=g
key=item.name
try: for d in groups:
found=form[key] if d.has_key(name) and d[name]==password: return name
if type(found) is lt: found.append(item)
else: if keys is None:
found=[found,item] # Not a named group, so don't go further
form[key]=found raise 'Forbidden', (
except: """<strong>You are not authorized to access this resource""")
form[key]=item
return None
request=self.request=Request(environ,form,stdin)
self.response=Response(stdout=stdout, stderr=stderr)
self.stdin=stdin
self.stdout=stdout
self.stderr=stderr
self.base=request.base
self.script=request.script
def publish_module(module_name, def publish_module(module_name,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
...@@ -1657,8 +1434,7 @@ def publish_module(module_name, ...@@ -1657,8 +1434,7 @@ def publish_module(module_name,
after_list=[None] after_list=[None]
try: try:
response=Response(stdout=stdout, stderr=stderr) response=Response(stdout=stdout, stderr=stderr)
publisher = CGIModulePublisher(stdin=stdin, stdout=stdout, publisher = ModulePublisher(stdin=stdin, stdout=stdout, stderr=stderr,
stderr=stderr,
environ=environ) environ=environ)
response = publisher.response response = publisher.response
response = publisher.publish(module_name,after_list,debug=debug) response = publisher.publish(module_name,after_list,debug=debug)
...@@ -1687,6 +1463,10 @@ def publish_module(module_name, ...@@ -1687,6 +1463,10 @@ def publish_module(module_name,
# #
# $Log: Publish.py,v $ # $Log: Publish.py,v $
# Revision 1.47 1997/09/02 21:18:53 jim
# Implemented new authorization model.
# No longer use Realm module.
#
# Revision 1.46 1997/07/28 22:01:58 jim # Revision 1.46 1997/07/28 22:01:58 jim
# Tries to get rid of base ref. # Tries to get rid of base ref.
# #
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment