Commit 16809f02 authored by 's avatar

Added support for domain-based authentication

parent 9c80bfbc
"""Access control package""" """Access control package"""
__version__='$Revision: 1.49 $'[11:-2] __version__='$Revision: 1.50 $'[11:-2]
import Globals, App.Undo, socket, regex
from PersistentMapping import PersistentMapping from PersistentMapping import PersistentMapping
from Persistence import Persistent from Persistence import Persistent
from Globals import HTMLFile, MessageDialog from Globals import HTMLFile, MessageDialog
...@@ -13,17 +13,28 @@ from OFS.SimpleItem import Item ...@@ -13,17 +13,28 @@ from OFS.SimpleItem import Item
from base64 import decodestring from base64 import decodestring
from ImageFile import ImageFile from ImageFile import ImageFile
from Role import RoleManager from Role import RoleManager
import Globals, App.Undo from string import split, join
ListType=type([]) ListType=type([])
class User(Implicit, Persistent): class User(Implicit, Persistent):
def __init__(self,name,password,roles):
# For backward compatibility
domains=[]
def __init__(self,name,password,roles,domains):
self.name =name self.name =name
self.roles=roles self.roles =roles
self.__ =password self.__ =password
self.domains=domains
def authenticate(self, password): def authenticate(self, password, request):
if self.domains:
return (password==self.__) and \
domainSpecMatch(self.domains, request)
return password==self.__ return password==self.__
def _shared_roles(self, parent): def _shared_roles(self, parent):
...@@ -92,15 +103,17 @@ try: ...@@ -92,15 +103,17 @@ try:
data=split(strip(f.readline()),':') data=split(strip(f.readline()),':')
f.close() f.close()
_remote_user_mode=not data[1] _remote_user_mode=not data[1]
super=User(data[0],data[1],('manage',)) try: ds=split(data[2], ' ')
except: ds=[]
super=User(data[0],data[1],('manage',), ds)
del data del data
except: except:
super=User('superuser','123',('manage',)) super=User('superuser','123',('manage',),[])
super.allowed=lambda parent, roles=None: 1
super.hasRole=lambda parent, roles=None: 1
super.has_role=lambda roles=None: 1 super.has_role=lambda roles=None: 1
super.hasRole=super.allowed
nobody=User('Anonymous User','',('Anonymous',)) nobody=User('Anonymous User','',('Anonymous',), [])
...@@ -152,10 +165,19 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -152,10 +165,19 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
def validate(self,request,auth='',roles=None): def validate(self,request,auth='',roles=None):
parent=request['PARENTS'][0] parent=request['PARENTS'][0]
# If no authorization, only nobody can match # If no authorization, only a user with a
# domain spec and no passwd or nobody can
# match
if not auth: if not auth:
if nobody.hasRole(parent, roles): for ob in self.data.values():
return nobody if ob.domains:
if ob.authenticate('', request):
if ob.allowed(parent, roles):
ob=ob.__of__(self)
return ob
if self._isTop() and nobody.allowed(parent, roles):
ob=nobody.__of__(self)
return ob
return None return None
# Only do basic authentication # Only do basic authentication
...@@ -165,7 +187,7 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -165,7 +187,7 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
# Check for superuser # Check for superuser
if self._isTop() and (name==super.name) and \ if self._isTop() and (name==super.name) and \
super.authenticate(password): super.authenticate(password, request):
return super return super
# Try to get user # Try to get user
...@@ -173,14 +195,14 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -173,14 +195,14 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
except: return None except: return None
# Try to authenticate user # Try to authenticate user
if not user.authenticate(password): if not user.authenticate(password, request):
return None return None
# We need the user to be able to acquire! # We need the user to be able to acquire!
user=user.__of__(self) user=user.__of__(self)
# Try to authorize user # Try to authorize user
if user.hasRole(parent, roles): if user.allowed(parent, roles):
return user return user
return None return None
...@@ -192,46 +214,80 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -192,46 +214,80 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
manage=manage_main=_mainUser manage=manage_main=_mainUser
def _addUser(self,name,password,confirm,roles,REQUEST=None): def _addUser(self,name,password,confirm,roles,domains,REQUEST=None):
if not name or not password or not confirm: if not name:
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='Name, password and confirmation must be specified', message='A username must be specified',
action ='manage_main')
if not password or not confirm:
if not domains:
return MessageDialog(
title ='Illegal value',
message='Password and confirmation must be specified',
action ='manage_main') action ='manage_main')
if self.data.has_key(name) or (name==super.name): if self.data.has_key(name) or (name==super.name):
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='A user with the specified name already exists', message='A user with the specified name already exists',
action ='manage_main') action ='manage_main')
if password!=confirm: if (password or confirm) and (password != confirm):
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='Password and confirmation do not match', message='Password and confirmation do not match',
action ='manage_main') action ='manage_main')
if not roles: roles=[] if not roles: roles=[]
self.data[name]=User(name,password,roles) if not domains: domains=[]
if domains and not domainSpecValidate(domains):
return MessageDialog(
title ='Illegal value',
message='Illegal domain specification',
action ='manage_main')
self.data[name]=User(name,password,roles,domains)
if REQUEST: return self._mainUser(self, REQUEST) if REQUEST: return self._mainUser(self, REQUEST)
def _changeUser(self,name,password,confirm,roles,REQUEST=None):
if not name or not password or not confirm: def _changeUser(self,name,password,confirm,roles,domains,REQUEST=None):
if not name:
return MessageDialog(
title ='Illegal value',
message='A username must be specified',
action ='manage_main')
if not password or not confirm:
if not domains:
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='Name, password and confirmation must be specified', message='Password and confirmation must be specified',
action ='manage_main') action ='manage_main')
if not self.data.has_key(name): if not self.data.has_key(name):
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='Unknown user', message='Unknown user',
action ='manage_main') action ='manage_main')
if password!=confirm: if (password or confirm) and (password != confirm):
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='Password and confirmation do not match', message='Password and confirmation do not match',
action ='manage_main') action ='manage_main')
if not roles: roles=[] if not roles: roles=[]
if not domains: domains=[]
if domains and not domainSpecValidate(domains):
return MessageDialog(
title ='Illegal value',
message='Illegal domain specification',
action ='manage_main')
user=self.data[name] user=self.data[name]
user.__=password user.__=password
user.roles=roles user.roles=roles
user.domains=domains
if REQUEST: return self._mainUser(self, REQUEST) if REQUEST: return self._mainUser(self, REQUEST)
def _delUsers(self,names,REQUEST=None): def _delUsers(self,names,REQUEST=None):
...@@ -268,14 +324,17 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -268,14 +324,17 @@ class UserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
password=reqattr(REQUEST, 'password') password=reqattr(REQUEST, 'password')
confirm =reqattr(REQUEST, 'confirm') confirm =reqattr(REQUEST, 'confirm')
roles =reqattr(REQUEST, 'roles') roles =reqattr(REQUEST, 'roles')
return self._addUser(name,password,confirm,roles,REQUEST) domains =reqattr(REQUEST, 'domains')
return self._addUser(name,password,confirm,roles,domains,REQUEST)
if submit=='Change': if submit=='Change':
name =reqattr(REQUEST, 'name') name =reqattr(REQUEST, 'name')
password=reqattr(REQUEST, 'password') password=reqattr(REQUEST, 'password')
confirm =reqattr(REQUEST, 'confirm') confirm =reqattr(REQUEST, 'confirm')
roles =reqattr(REQUEST, 'roles') roles =reqattr(REQUEST, 'roles')
return self._changeUser(name,password,confirm,roles,REQUEST) domains =reqattr(REQUEST, 'domains')
return self._changeUser(name,password,confirm,roles,
domains,REQUEST)
if submit=='Delete': if submit=='Delete':
names=reqattr(REQUEST, 'names') names=reqattr(REQUEST, 'names')
...@@ -312,8 +371,15 @@ if _remote_user_mode: ...@@ -312,8 +371,15 @@ if _remote_user_mode:
e=request.environ e=request.environ
if e.has_key('REMOTE_USER'): name=e['REMOTE_USER'] if e.has_key('REMOTE_USER'): name=e['REMOTE_USER']
else: else:
if nobody.hasRole(parent, roles): for ob in self.data.values():
return nobody if ob.domains:
if ob.authenticate('', request):
if ob.allowed(parent, roles):
ob=ob.__of__(self)
return ob
if self._isTop() and nobody.allowed(parent, roles):
ob=nobody.__of__(self)
return ob
return None return None
# Check for superuser # Check for superuser
...@@ -328,7 +394,7 @@ if _remote_user_mode: ...@@ -328,7 +394,7 @@ if _remote_user_mode:
user=user.__of__(self) user=user.__of__(self)
# Try to authorize user # Try to authorize user
if user.hasRole(parent, roles): if user.allowed(parent, roles):
return user return user
...@@ -342,6 +408,84 @@ def manage_addUserFolder(self,dtself=None,REQUEST=None,**ignored): ...@@ -342,6 +408,84 @@ def manage_addUserFolder(self,dtself=None,REQUEST=None,**ignored):
self.__allow_groups__=self.acl_users self.__allow_groups__=self.acl_users
if REQUEST: return self.manage_main(self,REQUEST,update_menu=1) if REQUEST: return self.manage_main(self,REQUEST,update_menu=1)
addr_match=regex.compile('[0-9\.\*]*').match
host_match=regex.compile('[A-Za-z0-9\.\*]*').match
def domainSpecValidate(spec):
for ob in spec:
sz=len(ob)
if not ((addr_match(ob) == sz) or (host_match(ob) == sz)):
return 0
return 1
def domainSpecMatch(spec, request):
if request.has_key('REMOTE_HOST'):
host=request['REMOTE_HOST']
else: host=''
if request.has_key('REMOTE_ADDR'):
addr=request['REMOTE_ADDR']
else: addr=''
if not host and not addr:
return 0
if not host:
host=socket.gethostbyaddr(addr)[0]
if not addr:
addr=socket.gethostbyname(host)
_host=split(host, '.')
_addr=split(addr, '.')
_hlen=len(_host)
_alen=len(_addr)
for ob in spec:
sz=len(ob)
_ob=split(ob, '.')
_sz=len(_ob)
if addr_match(ob)==sz:
if _sz != _alen:
continue
fail=0
for i in range(_sz):
a=_addr[i]
o=_ob[i]
if (o != a) and (o != '*'):
fail=1
break
if fail:
continue
return 1
if host_match(ob)==sz:
if _hlen < _sz:
continue
elif _hlen > _sz:
_item=_host[-_sz:]
else:
_item=_host
fail=0
for i in range(_sz):
h=_item[i]
o=_ob[i]
if (o != h) and (o != '*'):
fail=1
break
if fail:
continue
return 1
return 0
def absattr(attr): def absattr(attr):
if callable(attr): return attr() if callable(attr): return attr()
return attr return attr
......
<HTML> <HTML>
<HEAD> <HEAD>
<TITLE>Security</TITLE> <TITLE>Security</TITLE>
<STYLE type="text/css">
<!--
TD {
font-size: 10pt;
color: black;
}
-->
</STYLE>
</HEAD> </HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555" ALINK="#77003B"> <BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555" ALINK="#77003B">
<!--#if manage_tabs--> <!--#if manage_tabs-->
...@@ -15,57 +25,73 @@ indicate where roles are assigned permissions. ...@@ -15,57 +25,73 @@ indicate where roles are assigned permissions.
<!--#with expr="_.namespace(valid_roles=valid_roles())"--> <!--#with expr="_.namespace(valid_roles=valid_roles())"-->
<FORM ACTION="manage_changePermissions" METHOD="POST"> <FORM ACTION="manage_changePermissions" METHOD="POST">
<TABLE> <TABLE>
<tr> <TR>
<!--#unless isTopLevelPrincipiaApplicationObject--> <!--#unless isTopLevelPrincipiaApplicationObject-->
<td> </td> <TD>
<STRONG>
Acquire<BR>permission<BR>settings?
</STRONG>
</TD>
<!--#/unless--> <!--#/unless-->
<td> </td> <TD>
<td aligh=left colspan=<!--#var expr="_.len(valid_roles)"-->> <STRONG>
<strong>Roles:</strong></th> Permission
</tr> </STRONG>
<tr> </TD>
<TD ALIGN="LEFT" COLSPAN="<!--#var expr="_.len(valid_roles)"-->">
<STRONG>
Roles
</STRONG>
</TD>
</TR>
<TR>
<!--#unless isTopLevelPrincipiaApplicationObject--> <!--#unless isTopLevelPrincipiaApplicationObject-->
<th>Acquire permission settings</th> <TD></TD>
<!--#/unless--> <!--#/unless-->
<th>Permission</th> <TD></TD>
<!--#in valid_roles--> <!--#in valid_roles-->
<th><a href="manage_roleForm?role_to_manage=<!--# <TD CLASS="bold">
var sequence-item url_quote-->"> <A HREF="manage_roleForm?role_to_manage=<!--#
<!--#var sequence-item--></a></th> var sequence-item url_quote-->"><!--#var sequence-item--></A>
</TD>
<!--#/in valid_roles--> <!--#/in valid_roles-->
</tr> </TR>
<!--#in permission_settings mapping--> <!--#in permission_settings mapping-->
<tr> <TR>
<!--#unless isTopLevelPrincipiaApplicationObject--> <!--#unless isTopLevelPrincipiaApplicationObject-->
<td align=center> <TD ALIGN="CENTER">
<input type=checkbox <INPUT TYPE="checkbox" NAME="a<!--#var sequence-index-->"
name=a<!--#var sequence-index-->
<!--#var acquire-->> <!--#var acquire-->>
</td> </TD>
<!--#/unless--> <!--#/unless-->
<th align=left> <TD ALIGN="LEFT">
<a href="manage_permissionForm?permission_to_manage=<!--# <A HREF="manage_permissionForm?permission_to_manage=<!--#
var name url_quote-->"> var name url_quote-->">
<!--#var name--></a></th> <!--#var name--></A>
</TD>
<!--#in roles mapping--> <!--#in roles mapping-->
<td align=center> <TD ALIGN="CENTER">
<input type=checkbox name=<!--#var name--> <!--#var checked-->> <INPUT TYPE="CHECKBOX" NAME="<!--#var name-->" <!--#var checked-->>
</td> </TD>
<!--#/in--> <!--#/in-->
</tr> </TR>
<!--#/in permission_settings--> <!--#/in permission_settings-->
<tr> <TR>
<!--#if isTopLevelPrincipiaApplicationObject--> <!--#if isTopLevelPrincipiaApplicationObject-->
<td colspan=<!--#var expr="_.len(valid_roles)+1"--> align=center> <TD COLSPAN="<!--#var expr="_.len(valid_roles)+1"-->" ALIGN="CENTER">
<!--#else--> <!--#else-->
<td colspan=<!--#var expr="_.len(valid_roles)+2"--> align=center> <TD COLSPAN="<!--#var expr="_.len(valid_roles)+2"-->" ALIGN="CENTER">
<!--#/if--> <!--#/if-->
<input type=submit value="Change"> <INPUT TYPE="SUBMIT" VALUE="Change">
</td></tr> </TD>
</table> </TR>
</form> </TABLE>
</FORM>
<!--#/with--> <!--#/with-->
<!--#if expr="meta_type != 'User Folder'"-->
<P> <P>
<FORM ACTION="manage_defined_roles" METHOD="POST"> <FORM ACTION="manage_defined_roles" METHOD="POST">
<TABLE CELLPADDING="2"> <TABLE CELLPADDING="2">
...@@ -102,6 +128,8 @@ indicate where roles are assigned permissions. ...@@ -102,6 +128,8 @@ indicate where roles are assigned permissions.
<!--#/if userdefined_roles--> <!--#/if userdefined_roles-->
</TABLE> </TABLE>
</FORM> </FORM>
<!--#/if-->
</BODY> </BODY>
</HTML> </HTML>
...@@ -21,6 +21,7 @@ and roles for the new user and click &quot;Add&quot;. ...@@ -21,6 +21,7 @@ and roles for the new user and click &quot;Add&quot;.
<INPUT TYPE="TEXT" NAME="name" SIZE="20"> <INPUT TYPE="TEXT" NAME="name" SIZE="20">
</TD> </TD>
</TR> </TR>
<!--#if remote_user_mode__--> <!--#if remote_user_mode__-->
<INPUT TYPE="HIDDEN" NAME="password" value="password"> <INPUT TYPE="HIDDEN" NAME="password" value="password">
<INPUT TYPE="HIDDEN" NAME="confirm" value="password"> <INPUT TYPE="HIDDEN" NAME="confirm" value="password">
...@@ -30,7 +31,7 @@ and roles for the new user and click &quot;Add&quot;. ...@@ -30,7 +31,7 @@ and roles for the new user and click &quot;Add&quot;.
<STRONG>Password</STRONG> <STRONG>Password</STRONG>
</TD> </TD>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<INPUT TYPE="PASSWORD" NAME="password" SIZE="20"> <INPUT TYPE="PASSWORD" NAME="password" SIZE="40">
</TD> </TD>
</TR> </TR>
<TR> <TR>
...@@ -38,10 +39,20 @@ and roles for the new user and click &quot;Add&quot;. ...@@ -38,10 +39,20 @@ and roles for the new user and click &quot;Add&quot;.
<STRONG>(Confirm)</STRONG> <STRONG>(Confirm)</STRONG>
</TD> </TD>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<INPUT TYPE="PASSWORD" NAME="confirm" SIZE="20"> <INPUT TYPE="PASSWORD" NAME="confirm" SIZE="40">
</TD> </TD>
</TR> </TR>
<!--#/if--> <!--#/if-->
<TR>
<TD VALIGN="TOP">
<STRONG>Domains</STRONG>
</TD>
<TD VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="domains:tokens" VALUE="" SIZE="40">
</TD>
</TR>
<TR> <TR>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<STRONG>Roles</STRONG> <STRONG>Roles</STRONG>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
<!--#var expr="user.name"--> <!--#var expr="user.name"-->
</TD> </TD>
</TR> </TR>
<!--#if remote_user_mode__--> <!--#if remote_user_mode__-->
<INPUT TYPE="HIDDEN" NAME="password" value="<!--#var password-->"> <INPUT TYPE="HIDDEN" NAME="password" value="<!--#var password-->">
<INPUT TYPE="HIDDEN" NAME="confirm" value="<!--#var password-->"> <INPUT TYPE="HIDDEN" NAME="confirm" value="<!--#var password-->">
...@@ -24,7 +25,7 @@ ...@@ -24,7 +25,7 @@
<STRONG>Password</STRONG> <STRONG>Password</STRONG>
</TD> </TD>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<INPUT TYPE="PASSWORD" NAME="password" VALUE="<!--#var password-->" SIZE="20"> <INPUT TYPE="PASSWORD" NAME="password" VALUE="<!--#var password-->" SIZE="40">
</TD> </TD>
</TR> </TR>
<TR> <TR>
...@@ -32,10 +33,20 @@ ...@@ -32,10 +33,20 @@
<STRONG>(Confirm)</STRONG> <STRONG>(Confirm)</STRONG>
</TD> </TD>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<INPUT TYPE="PASSWORD" NAME="confirm" VALUE="<!--#var password-->" SIZE="20"> <INPUT TYPE="PASSWORD" NAME="confirm" VALUE="<!--#var password-->" SIZE="40">
</TD> </TD>
</TR> </TR>
<!--#/if--> <!--#/if-->
<TR>
<TD VALIGN="TOP">
<STRONG>Domains</STRONG>
</TD>
<TD VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="domains:tokens" VALUE="<!--#if expr="user.domains"--><!--#in expr="user.domains"--><!--#var sequence-item--> <!--#/in--><!--#/if-->" SIZE="40">
</TD>
</TR>
<TR> <TR>
<TD VALIGN="TOP"> <TD VALIGN="TOP">
<STRONG>Roles</STRONG> <STRONG>Roles</STRONG>
......
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