Commit 16809f02 authored by 's avatar

Added support for domain-based authentication

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