Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
cd3063f9
Commit
cd3063f9
authored
Mar 28, 2005
by
Tres Seaver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Check in my acquisition / security noodling for Jim to play with.
parent
c611580e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
379 additions
and
83 deletions
+379
-83
lib/python/AccessControl/ImplPython.py
lib/python/AccessControl/ImplPython.py
+54
-32
lib/python/AccessControl/cAccessControl.c
lib/python/AccessControl/cAccessControl.c
+66
-49
lib/python/AccessControl/tests/testAcquisition.py
lib/python/AccessControl/tests/testAcquisition.py
+252
-0
lib/python/Shared/DC/Scripts/Bindings.py
lib/python/Shared/DC/Scripts/Bindings.py
+7
-2
No files found.
lib/python/AccessControl/ImplPython.py
View file @
cd3063f9
...
@@ -17,6 +17,9 @@ import os
...
@@ -17,6 +17,9 @@ import os
import
string
import
string
from
Acquisition
import
aq_base
from
Acquisition
import
aq_base
from
Acquisition
import
aq_parent
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_acquire
from
ExtensionClass
import
Base
from
ExtensionClass
import
Base
from
zLOG
import
LOG
,
PROBLEM
from
zLOG
import
LOG
,
PROBLEM
...
@@ -522,38 +525,57 @@ def guarded_getattr(inst, name, default=_marker):
...
@@ -522,38 +525,57 @@ def guarded_getattr(inst, name, default=_marker):
Raises Unauthorized if the attribute is found but the user is
Raises Unauthorized if the attribute is found but the user is
not allowed to access the attribute.
not allowed to access the attribute.
"""
"""
if
name
[:
1
]
!=
'_'
:
if
name
[:
1
]
==
'_'
:
# Try to get the attribute normally so that unusual
raise
Unauthorized
,
name
# exceptions are caught early.
try
:
v
=
getattr
(
inst
,
name
)
# Try to get the attribute normally so that unusual
except
AttributeError
:
# exceptions are caught early.
if
default
is
not
_marker
:
try
:
return
default
v
=
getattr
(
inst
,
name
)
raise
except
AttributeError
:
if
default
is
not
_marker
:
assertion
=
Containers
(
type
(
inst
))
return
default
if
isinstance
(
assertion
,
dict
):
raise
# We got a table that lets us reason about individual
# attrs
return
_verify_attribute_access
(
inst
,
name
,
v
)
assertion
=
assertion
.
get
(
name
)
if
assertion
:
def
_verify_attribute_access
(
inst
,
name
,
v
):
# There's an entry, but it may be a function.
if
callable
(
assertion
):
try
:
return
assertion
(
inst
,
name
)
container
=
v
.
im_self
except
AttributeError
:
# Nope, it's boolean
container
=
aq_parent
(
aq_inner
(
v
))
or
inst
return
v
raise
Unauthorized
,
name
assertion
=
Containers
(
type
(
container
))
elif
assertion
:
if
isinstance
(
assertion
,
dict
):
# So the entry in the outer table is not a dict
# We got a table that lets us reason about individual
# It's allowed to be a vetoing function:
# attrs
assertion
=
assertion
.
get
(
name
)
if
assertion
:
# There's an entry, but it may be a function.
if
callable
(
assertion
):
if
callable
(
assertion
):
assertion
(
name
,
v
)
return
assertion
(
inst
,
name
)
# No veto, so we can return
return
v
validate
=
SecurityManagement
.
getSecurityManager
().
validate
# Nope, it's boolean
if
validate
(
inst
,
inst
,
name
,
v
):
return
v
return
v
raise
Unauthorized
,
name
raise
Unauthorized
,
name
if
assertion
:
if
callable
(
assertion
):
factory
=
assertion
(
name
,
v
)
if
callable
(
factory
):
return
factory
(
inst
,
name
)
assert
factory
==
1
else
:
assert
assertion
==
1
return
v
# See if we can get the value doing a filtered acquire.
# aq_acquire will either return the same value as held by
# v or it will return an Unauthorized raised by validate.
validate
=
SecurityManagement
.
getSecurityManager
().
validate
aq_acquire
(
inst
,
name
,
aq_validate
,
validate
)
return
v
lib/python/AccessControl/cAccessControl.c
View file @
cd3063f9
...
@@ -2080,8 +2080,13 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
...
@@ -2080,8 +2080,13 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
int
i
;
int
i
;
/* if name[:1] != '_': */
/* if name[:1] != '_': */
if
(
(
PyString_Check
(
name
)
||
PyUnicode_Check
(
name
))
&&
if
(
PyString_Check
(
name
)
||
PyUnicode_Check
(
name
))
{
PyString_AsString
(
name
)[
0
]
!=
'_'
)
char
*
name_s
=
PyString_AsString
(
name
);
if
(
name_s
==
NULL
)
return
NULL
;
if
(
name_s
[
0
]
!=
'_'
)
{
{
/*
/*
...
@@ -2107,31 +2112,27 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
...
@@ -2107,31 +2112,27 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
}
}
/*
/*
assertion = Containers(type(inst))
if type(assertion) is DictType:
assertion = Containers(type(inst))
# We got a table that lets us reason about individual
# attrs
assertion = assertion.get(name)
if assertion:
# There's an entry, but it may be a function.
if callable(assertion):
return assertion(inst, name)
# Nope, it's boolean
return v
raise Unauthorized, name
elif assertion:
# So the entry in the outer table is not a dict
# It's allowed to be a vetoing function:
if callable(assertion):
assertion(name, v)
# No veto, so we can return
return v
*/
*/
t
=
PyDict_GetItem
(
ContainerAssertions
,
OBJECT
(
inst
->
ob_type
));
t
=
PyDict_GetItem
(
ContainerAssertions
,
OBJECT
(
inst
->
ob_type
));
if
(
t
!=
NULL
)
if
(
t
!=
NULL
)
{
{
/*
if isinstance(assertion, dict):
# We got a table that lets us reason about individual
# attrs
assertion = assertion.get(name)
if assertion:
# There's an entry, but it may be a function.
if callable(assertion):
return assertion(inst, name)
# Nope, it's boolean
return v
raise Unauthorized, name
*/
if
(
PyDict_Check
(
t
))
if
(
PyDict_Check
(
t
))
{
{
PyObject
*
attrv
;
PyObject
*
attrv
;
...
@@ -2155,43 +2156,59 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
...
@@ -2155,43 +2156,59 @@ guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
Py_DECREF
(
v
);
Py_DECREF
(
v
);
goto
unauth
;
goto
unauth
;
}
}
i
=
PyObject_IsTrue
(
t
);
/*
if
(
i
<
0
)
goto
err
;
if assertion:
if
(
i
)
if callable(assertion):
factory = assertion(name, v)
if callable(factory):
return factory(inst, name)
assert factory == 1
assert callable == 1
return v
*/
if
(
PyCallable_Check
(
t
))
{
{
if
(
t
->
ob_type
->
tp_call
)
PyObject
*
factory
;
factory
=
callfunction2
(
t
,
name
,
v
);
if
(
factory
==
NULL
)
goto
err
;
if
(
PyCallable_Check
(
factory
))
{
{
PyObject
*
ignored
;
Py_DECREF
(
v
);
ignored
=
callfunction2
(
t
,
name
,
v
);
v
=
callfunction2
(
factory
,
inst
,
name
);
if
(
ignored
==
NULL
)
{
/* veto */
Py_DECREF
(
v
);
return
NULL
;
}
Py_DECREF
(
ignored
);
}
}
return
v
;
Py_DECREF
(
factory
)
;
}
}
return
v
;
}
}
/*
/*
if validate(inst, inst, name, v):
# See if we can get the value doing a filtered acquire.
return v
# aq_acquire will either return the same value as held by
*/
# v or it will return an Unauthorized raised by validate.
validate
=
callfunction4
(
validate
,
inst
,
inst
,
name
,
v
);
validate = SecurityManagement.getSecurityManager().validate
if
(
validate
==
NULL
)
goto
err
;
aq_acquire(inst, name, aq_validate, validate)
i
=
PyObject_IsTrue
(
validate
);
Py_DECREF
(
validate
);
return v
if
(
i
<
0
)
goto
err
;
*/
if
(
i
>
0
)
return
v
;
t
=
aq_Acquire
(
inst
,
name
,
aq_validate
,
validate
,
1
,
NULL
,
0
);
if
(
t
==
NULL
)
return
NULL
;
Py_DECREF
(
t
);
return
v
;
unauthErr
(
name
,
v
);
unauthErr
(
name
,
v
);
err:
err:
Py_DECREF
(
v
);
Py_DECREF
(
v
);
return
NULL
;
return
NULL
;
}
}
}
unauth:
unauth:
/* raise Unauthorized, name */
/* raise Unauthorized, name */
...
...
lib/python/AccessControl/tests/testAcquisition.py
0 → 100644
View file @
cd3063f9
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Tests demonstrating consequences of guarded_getattr fix from 2004/08/07
http://mail.zope.org/pipermail/zope-checkins/2004-August/028152.html
http://zope.org/Collectors/CMF/259
"""
import
unittest
from
Testing.makerequest
import
makerequest
import
Zope2
Zope2
.
startup
()
from
OFS.SimpleItem
import
SimpleItem
from
Globals
import
InitializeClass
from
AccessControl
import
ClassSecurityInfo
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
AccessControl.Permissions
import
view
,
view_management_screens
from
AccessControl.ImplPython
import
guarded_getattr
as
guarded_getattr_py
from
AccessControl.ImplC
import
guarded_getattr
as
guarded_getattr_c
from
Products.SiteErrorLog.SiteErrorLog
import
SiteErrorLog
class
AllowedItem
(
SimpleItem
):
id
=
'allowed'
security
=
ClassSecurityInfo
()
security
.
setDefaultAccess
(
'allow'
)
InitializeClass
(
AllowedItem
)
class
DeniedItem
(
SimpleItem
):
id
=
'denied'
security
=
ClassSecurityInfo
()
security
.
setDefaultAccess
(
'deny'
)
InitializeClass
(
DeniedItem
)
class
ProtectedItem
(
SimpleItem
):
id
=
'protected'
security
=
ClassSecurityInfo
()
security
.
declareObjectProtected
(
view_management_screens
)
InitializeClass
(
ProtectedItem
)
class
ProtectedSiteErrorLog
(
SiteErrorLog
):
'''This differs from the base by declaring security
for the object itself.
'''
id
=
'error_log2'
security
=
ClassSecurityInfo
()
security
.
declareObjectProtected
(
view
)
InitializeClass
(
ProtectedSiteErrorLog
)
class
TestGetAttr
(
unittest
.
TestCase
):
def
setUp
(
self
):
import
transaction
self
.
guarded_getattr
=
guarded_getattr_py
transaction
.
manager
.
begin
()
self
.
app
=
makerequest
(
Zope2
.
app
())
try
:
# Set up a manager user
self
.
uf
=
self
.
app
.
acl_users
self
.
uf
.
_doAddUser
(
'manager'
,
'secret'
,
[
'Manager'
],
[])
self
.
login
(
'manager'
)
# Set up objects in the root that we want to aquire
self
.
app
.
manage_addFolder
(
'plain_folder'
)
self
.
app
.
_setObject
(
'error_log2'
,
ProtectedSiteErrorLog
())
# We also want to be able to acquire simple attributes
self
.
app
.
manage_addProperty
(
id
=
'simple_type'
,
type
=
'string'
,
value
=
'a string'
)
# Set up a subfolder and the objects we want to acquire from
self
.
app
.
manage_addFolder
(
'subfolder'
)
self
.
folder
=
self
.
app
.
subfolder
self
.
folder
.
_setObject
(
'allowed'
,
AllowedItem
())
self
.
folder
.
_setObject
(
'denied'
,
DeniedItem
())
self
.
folder
.
_setObject
(
'protected'
,
ProtectedItem
())
except
:
self
.
tearDown
()
raise
def
tearDown
(
self
):
import
transaction
noSecurityManager
()
transaction
.
manager
.
get
().
abort
()
self
.
app
.
_p_jar
.
close
()
def
login
(
self
,
name
):
user
=
self
.
uf
.
getUserById
(
name
)
user
=
user
.
__of__
(
self
.
uf
)
newSecurityManager
(
None
,
user
)
# Acquire plain folder
def
testFolderAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'plain_folder'
)
self
.
assertEqual
(
o
,
self
.
app
.
plain_folder
)
def
testFolderDenied
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'plain_folder'
)
self
.
assertEqual
(
o
,
self
.
app
.
plain_folder
)
def
testFolderProtected
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'plain_folder'
)
self
.
assertEqual
(
o
,
self
.
app
.
plain_folder
)
# Acquire user folder
def
testAclUsersAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'acl_users'
)
self
.
assertEqual
(
o
,
self
.
app
.
acl_users
)
def
testAclUsersDenied
(
self
):
# XXX: Fails in 2.7.3
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'acl_users'
)
self
.
assertEqual
(
o
,
self
.
app
.
acl_users
)
def
testAclUsersProtected
(
self
):
# XXX: Fails in 2.7.3 for Anonymous
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'acl_users'
)
self
.
assertEqual
(
o
,
self
.
app
.
acl_users
)
# Acquire browser id manager
def
testBrowserIdManagerAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'browser_id_manager'
)
self
.
assertEqual
(
o
,
self
.
app
.
browser_id_manager
)
def
testBrowserIdManagerDenied
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'browser_id_manager'
)
self
.
assertEqual
(
o
,
self
.
app
.
browser_id_manager
)
def
testBrowserIdManagerProtected
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'browser_id_manager'
)
self
.
assertEqual
(
o
,
self
.
app
.
browser_id_manager
)
# Acquire error log
def
testErrorLogAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'error_log'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log
)
def
testErrorLogDenied
(
self
):
# XXX: Fails in 2.7.3
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'error_log'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log
)
def
testErrorLogProtected
(
self
):
# XXX: Fails in 2.7.3 for Anonymous
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'error_log'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log
)
# Now watch this: error log with object security declaration works fine!
def
testProtectedErrorLogAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'error_log2'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log2
)
def
testProtectedErrorLogDenied
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'error_log2'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log2
)
def
testProtectedErrorLogProtected
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'error_log2'
)
self
.
assertEqual
(
o
,
self
.
app
.
error_log2
)
# This appears to mean that any potential acquiree must make sure
# to declareObjectProtected(SomePermission).
# From the ZDG:
# We've seen how to make assertions on methods - but in the case of
# someObject we are not trying to access any particular method, but
# rather the object itself (to pass it to some_method). Because the
# security machinery will try to validate access to someObject, we
# need a way to let the security machinery know how to handle access
# to the object itself in addition to protecting its methods.
# IOW, acquiring an object in restricted Python now amounts to
# "passing it to some_method".
# Also test Richard Jones' use-case of acquiring a string:
def
testSimpleTypeAllowed
(
self
):
o
=
self
.
guarded_getattr
(
self
.
folder
.
allowed
,
'simple_type'
)
self
.
assertEqual
(
o
,
'a string'
)
def
testSimpleTypeDenied
(
self
):
# XXX: Fails in 2.7.3
o
=
self
.
guarded_getattr
(
self
.
folder
.
denied
,
'simple_type'
)
self
.
assertEqual
(
o
,
'a string'
)
def
testSimpleTypeProtected
(
self
):
# XXX: Fails in 2.7.3 for Anonymous
o
=
self
.
guarded_getattr
(
self
.
folder
.
protected
,
'simple_type'
)
self
.
assertEqual
(
o
,
'a string'
)
class
TestGetAttrAnonymous
(
TestGetAttr
):
# Run all tests again as Anonymous User
def
setUp
(
self
):
TestGetAttr
.
setUp
(
self
)
# Log out
noSecurityManager
()
class
TestGetAttr_c
(
TestGetAttr
):
def
setUp
(
self
):
TestGetAttr
.
setUp
(
self
)
self
.
guarded_getattr
=
guarded_getattr_c
class
TestGetAttrAnonymous_c
(
TestGetAttrAnonymous
):
def
setUp
(
self
):
TestGetAttrAnonymous
.
setUp
(
self
)
self
.
guarded_getattr
=
guarded_getattr_c
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestGetAttr
))
suite
.
addTest
(
unittest
.
makeSuite
(
TestGetAttrAnonymous
))
suite
.
addTest
(
unittest
.
makeSuite
(
TestGetAttr_c
))
suite
.
addTest
(
unittest
.
makeSuite
(
TestGetAttrAnonymous_c
))
return
suite
if
__name__
==
'__main__'
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
lib/python/Shared/DC/Scripts/Bindings.py
View file @
cd3063f9
...
@@ -15,6 +15,7 @@ __version__='$Revision$'[11:-2]
...
@@ -15,6 +15,7 @@ __version__='$Revision$'[11:-2]
import
Globals
import
Globals
from
AccessControl
import
getSecurityManager
from
AccessControl
import
getSecurityManager
from
AccessControl.PermissionRole
import
_what_not_even_god_should_do
from
AccessControl.ZopeGuards
import
guarded_getattr
from
AccessControl.ZopeGuards
import
guarded_getattr
from
Persistence
import
Persistent
from
Persistence
import
Persistent
from
string
import
join
,
strip
from
string
import
join
,
strip
...
@@ -167,15 +168,19 @@ class UnauthorizedBinding:
...
@@ -167,15 +168,19 @@ class UnauthorizedBinding:
self
.
_wrapped
=
wrapped
self
.
_wrapped
=
wrapped
__allow_access_to_unprotected_subobjects__
=
1
__allow_access_to_unprotected_subobjects__
=
1
__roles__
=
_what_not_even_god_should_do
def
__getattr__
(
self
,
name
,
default
=
None
):
def
__repr__
(
self
):
return
'<UnauthorizedBinding: %s>'
%
self
.
_name
def
__getattr__
(
self
,
name
,
default
=
None
):
# Make *extra* sure that the wrapper isn't used to access
# Make *extra* sure that the wrapper isn't used to access
# __call__,
__str__, __repr__,
etc.
# __call__, etc.
if
name
.
startswith
(
'__'
):
if
name
.
startswith
(
'__'
):
self
.
__you_lose
()
self
.
__you_lose
()
return
guarded_getattr
(
self
.
_wrapped
,
name
,
default
)
return
guarded_getattr
(
self
.
_wrapped
,
name
,
default
)
#return getattr(self._wrapped, name, default)
def
__you_lose
(
self
):
def
__you_lose
(
self
):
name
=
self
.
__dict__
[
'_name'
]
name
=
self
.
__dict__
[
'_name'
]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment