This repository has been archived by the owner on Apr 16, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Patrick Bernard
committed
May 23, 2006
1 parent
b2636d2
commit bd5ec74
Showing
9 changed files
with
441 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
version 0.0.1 Initial release: works for me | ||
|
||
version 0.0.2 Changed detection in modifyRequest to check Content-Type | ||
and Request-Method | ||
|
||
version 0.0.3 Added add, list, remove methods so product coders can | ||
register their functions to avoid prefixing username and passwords. | ||
Changed modifyRequest to not check Content-Type. | ||
|
||
version 0.4 Zope 2.7 support. Work if unicode path is passed in. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
NAME=RPCAuth | ||
MAJOR_VERSION=0.1 | ||
MINOR_VERSION=0 | ||
RELEASE_TAG=final | ||
PACKAGE_NAME=${NAME}-${MAJOR_VERSION}.${MINOR_VERSION}_${RELEASE_TAG} | ||
|
||
PYTHON="/usr/bin/python" | ||
TMPDIR=~/tmp | ||
|
||
CURDIR=~/src/collective/RPCAuth | ||
BASE_DIR=${CURDIR}/.. | ||
SOFTWARE_HOME=~/src/zope/2_7/lib/python | ||
INSTANCE_HOME=~/src/instance/head | ||
PACKAGES=RPCAuth | ||
|
||
|
||
RM=rm -f | ||
RMRF=rm -rf | ||
FIND=find | ||
XARGS=xargs | ||
CD=cd | ||
LN=ln -sfn | ||
CP=cp | ||
TAR=tar | ||
MKDIR=mkdir -p | ||
|
||
.PHONY : clean test reindent reindent_clean sdist | ||
.PHONY : default | ||
|
||
# default: The default step (invoked when make is called without a target) | ||
default: clean test | ||
|
||
clean : | ||
find . \( -name '*~' -o -name '*.py[co]' -o -name '*.bak' \) -exec rm {} \; -print | ||
|
||
reindent : | ||
~/src/reindent.py -r -v . | ||
|
||
test : | ||
export INSTANCE_HOME=${INSTANCE_HOME}; export SOFTWARE_HOME=${SOFTWARE_HOME}; \ | ||
cd ${CURDIR}/tests && ${PYTHON} runalltests.py | ||
|
||
|
||
# sdist: Create a source distribution file (implies clean). | ||
# | ||
sdist: reindent clean sdist_tgz | ||
|
||
# sdist_tgz: Create a tgz archive file as a source distribution. | ||
# | ||
sdist_tgz: | ||
echo -n "${MAJOR_VERSION}.${MINOR_VERSION}-${RELEASE_TAG}" >\ | ||
${CURDIR}/version.txt | ||
${MKDIR} ${TMPDIR}/${PACKAGE_NAME} | ||
${CD} ${TMPDIR}/${PACKAGE_NAME} && \ | ||
for package in ${PACKAGES}; do ${LN} ${BASE_DIR}/$$package .; done && \ | ||
${CD} ${TMPDIR} && ${TAR} czfh ${BASE_DIR}/${PACKAGE_NAME}.tgz ${PACKAGE_NAME} \ | ||
--exclude=${PACKAGE_NAME}.tgz\ | ||
--exclude=CVS \ | ||
--exclude=.cvsignore \ | ||
--exclude=makefile \ | ||
--exclude=Makefile \ | ||
--exclude=*.pyc \ | ||
--exclude=TAGS \ | ||
--exclude=*~ \ | ||
--exclude=.#* | ||
${RMRF} ${TMPDIR}/${PACKAGE_NAME} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
RPCAuth is a rip off of the great CookieCrumbler product. It is | ||
designed to allow users of XML-RPC methods to pass their username and | ||
password as arguments. It works on the same principle as the | ||
CookieCrumbler allowing the transparent use of existing UserFolders, | ||
just add a RPCAuth instance to the folder where your acl_users is | ||
located. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
""" | ||
RPCAuth is a pretraversal hook that checks for xmlrpc calls and | ||
tries to extract a username and password from the arguements passed | ||
""" | ||
|
||
import sys | ||
from base64 import encodestring | ||
from urllib import quote, unquote | ||
from os import path | ||
import string | ||
from DateTime import DateTime | ||
from utils import SimpleItemWithProperties | ||
from AccessControl import ClassSecurityInfo, Permissions | ||
from ZPublisher import BeforeTraverse | ||
import Globals | ||
from zLOG import LOG, ERROR | ||
from App.Common import package_home | ||
from ZPublisher.HTTPRequest import HTTPRequest | ||
|
||
# Constants. | ||
ATTEMPT_DISABLED = -1 | ||
ATTEMPT_NONE = 0 | ||
ATTEMPT_LOGIN = 1 | ||
ATTEMPT_CONT = 2 | ||
|
||
ModifyRPCAuth = 'Change RPC Auth' | ||
|
||
|
||
class RPCAuth(SimpleItemWithProperties): | ||
''' | ||
Reads xmlrpc args during traversal and simulates the HTTP | ||
authentication headers. | ||
''' | ||
meta_type = 'RPC Auth' | ||
security = ClassSecurityInfo() | ||
security.declareProtected(ModifyRPCAuth, | ||
'manage_editProperties', | ||
'manage_changeProperties') | ||
security.declareProtected(Permissions.view_management_screens, | ||
'manage_propertiesForm') | ||
|
||
|
||
_properties = ({'id':'uname_arg', 'type': 'string', 'mode':'w', | ||
'label':'User name arguement prefix'}, | ||
{'id':'pword_arg', 'type': 'string', 'mode':'w', | ||
'label':'User password arguement prefix'}, | ||
{'id':'remove_args','type':'boolean','mode':'w', | ||
'label':'Remove password username arguements'}, | ||
) | ||
|
||
def __init__(self): | ||
self.remove_args = 1 | ||
self.uname_arg = 'zid' | ||
self.pword_arg = 'zpw' | ||
self._authProviders = {'absglob':{},'abs':{},'rel':{}} | ||
|
||
|
||
security.declareProtected(ModifyRPCAuth,'addAuthProvider') | ||
def addAuthProvider(self,objectPaths,function): | ||
"""takes a list of paths and a function as an arguements""" | ||
aps = getattr(self,'_authProviders',{'absglob':{},'abs':{},'rel':{}}) | ||
for name in list(objectPaths): | ||
if name[-1] == '/' and name[0] == '/': # absolute glob | ||
aps['absglob'][tuple(string.split(name,'/')[1:-1])] = function | ||
if name[0] == '/': # absolute url | ||
aps['abs'][tuple(string.split(name,'/')[1:])] = function | ||
if name[0] != '/' and name[-1] != '/' and '/' in name: # relative | ||
aps['rel'][tuple(string.split(name,'/'))] = function | ||
self._authProviders = aps | ||
self._p_changed = 1 | ||
|
||
security.declareProtected(ModifyRPCAuth,'listAuthProviders') | ||
def listAuthProviders(self): | ||
"""a list of objects with auth providers""" | ||
aps = getattr(self,'_authProviders',{'absglob':{},'abs':{},'rel':{}}) | ||
return aps['absglob'].keys()+\ | ||
aps['abs'].keys()+\ | ||
aps['rel'].keys() | ||
|
||
security.declareProtected(ModifyRPCAuth,'removeAuthProvider') | ||
def removeAuthProvider(self,objectPaths): | ||
"""remove auth providers objectPaths should be a list""" | ||
for objectPath in list(objectPaths): | ||
if type(objectPath) == type('s'): | ||
objectPath = string.split(objectPath,'/') | ||
while '' in objectPath: del objectPath[objectPath.index('')] | ||
tuple(objectPath) | ||
if objectPath in self._authProviders['absglob'].keys(): | ||
del self._authProviders['absglob'][objectPath] | ||
elif objectPath in self._authProviders['abs'].keys(): | ||
del self._authProviders['abs'][objectPath] | ||
elif objectPath in self._authProviders['rel'].keys(): | ||
del self._authProviders['rel'][objectPath] | ||
|
||
|
||
def _identify(self,arg_tuple): | ||
arg_list = list(arg_tuple) | ||
zusername,zpassword = None,None | ||
try: | ||
for item in arg_tuple: #use the tuple here so we can delete items as we iterate | ||
if type(item) == type('') and len(item) > len(self.uname_arg) and item[:len(self.uname_arg)] == self.uname_arg: | ||
zusername = item[len(self.uname_arg):] | ||
del arg_list[arg_list.index(item)] | ||
continue | ||
if type(item) == type('') and len(item) > len(self.uname_arg) and item[:len(self.pword_arg)] == self.pword_arg: | ||
zpassword = item[len(self.pword_arg):] | ||
del arg_list[arg_list.index(item)] | ||
if zusername and zpassword: | ||
arg_tuple = tuple(arg_list) | ||
return zusername,zpassword,arg_tuple | ||
else: | ||
return None,None,None | ||
except 'none': | ||
return None | ||
|
||
def _registryIdentify(self,targetPath): | ||
targetPath = list(targetPath) | ||
targetPath.reverse() | ||
targetPath = [a.encode('utf-8') for a in targetPath] | ||
targetPath = tuple(targetPath) | ||
# first check absolute path cuz it's easy | ||
if targetPath in self._authProviders['abs'].keys(): | ||
return self._authProviders['abs'][targetPath] | ||
# check relative paths | ||
relPath = targetPath[:] | ||
while len(relPath) > 1: | ||
if relPath in self._authProviders['rel'].keys(): | ||
return self._authProviders['rel'][relPath] | ||
relPath= relPath[1:] | ||
# check absolute globs | ||
globPath = targetPath[:-1] | ||
while len(globPath) > 1: | ||
if globPath in self._authProviders['absglob'].keys(): | ||
return self._authProviders['absglob'][globPath] | ||
globPath=globPath[:-1] | ||
return None | ||
|
||
security.declarePrivate('modifyRequest') | ||
def modifyRequest(self, req, resp): | ||
# Returns flags indicating what the user is trying to do. | ||
|
||
if req.__class__ is not HTTPRequest: | ||
return ATTEMPT_DISABLED | ||
|
||
if not req._auth: | ||
# Attempt to log in. | ||
targetPath = tuple(req['TraversalRequestNameStack']) | ||
authProvider = self._registryIdentify(targetPath) | ||
if authProvider: | ||
name,pw,arg_tuple = authProvider(req.args) | ||
else: | ||
name,pw,arg_tuple = self._identify(req.args) | ||
if name and pw: | ||
ac = encodestring('%s:%s' % (name, pw)) | ||
req._auth = 'basic %s' % ac | ||
resp._auth = 1 | ||
if self.remove_args or authProvider: # if we set remove_args or an authProvider is used | ||
req.args = arg_tuple | ||
return ATTEMPT_LOGIN | ||
return ATTEMPT_NONE | ||
|
||
def __call__(self, container, req): | ||
'''The __before_publishing_traverse__ hook.''' | ||
resp = self.REQUEST['RESPONSE'] | ||
attempt = self.modifyRequest(req, resp) | ||
|
||
|
||
def _cleanupResponse(self): | ||
resp = self.REQUEST['RESPONSE'] | ||
try: del resp.unauthorized | ||
except: pass | ||
try: del resp._unauthorized | ||
except: pass | ||
return resp | ||
|
||
|
||
|
||
security.declarePrivate('unauthorized') | ||
def unauthorized(self): | ||
resp.unauthorized() | ||
|
||
def _unauthorized(self): | ||
resp._unauthorized() | ||
|
||
|
||
# Installation and removal of traversal hooks. | ||
|
||
def manage_beforeDelete(self, item, container): | ||
if item is self: | ||
handle = self.meta_type + '/' + self.getId() | ||
BeforeTraverse.unregisterBeforeTraverse(container, handle) | ||
|
||
def manage_afterAdd(self, item, container): | ||
if item is self: | ||
handle = self.meta_type + '/' + self.getId() | ||
container = container.this() | ||
nc = BeforeTraverse.NameCaller(self.getId()) | ||
BeforeTraverse.registerBeforeTraverse(container, nc, handle) | ||
|
||
Globals.InitializeClass(RPCAuth) | ||
|
||
def manage_addRAForm(self): | ||
"this is a form to get the id" | ||
return """<html> | ||
<head> | ||
<title>Setup RPC Auth</title> | ||
</head> | ||
<body> | ||
Please type the id of the RPC Auth:<br> | ||
<form name="form" action="manage_addRPCAuth"><br> | ||
<input type="text" name="id"><br> | ||
<input type="submit" value="add"> | ||
</form> | ||
</body> | ||
</html>""" | ||
|
||
def manage_addRPCAuth(self, id, REQUEST=None): | ||
' ' | ||
ob = RPCAuth() | ||
ob.id = id | ||
self._setObject(id, ob) | ||
if REQUEST is not None: | ||
return self.manage_main(self, REQUEST) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import RPCAuth | ||
|
||
def initialize(context): | ||
context.registerClass( | ||
RPCAuth.RPCAuth, | ||
constructors=(RPCAuth.manage_addRAForm, | ||
RPCAuth.manage_addRPCAuth), | ||
icon = 'RPCAuth.gif' | ||
) |
Empty file.
Oops, something went wrong.