Using Group Folders
===================

Group folders are used to define groups.  Before you can define
groups, you have to create a group folder and configure it in a
pluggable authentication utility. The group folder has to be
registered with a pluggable authentication utility before defining any
groups.  This is because the groups folder needs to use the pluggable
authentication utility to find all of the groups containing a given
group so that it can check for group cycles. Not all of a group's
groups need to be defined in it's group folder. Other groups folders
or group-defining plugins could define groups for a group.

Let's walk through an example.

First, we'll create a principal folder:

  (The first request is a bit weird.  It is part of the current
   tools UI.  It arranges for a tools site-management folder to be
   created.  We really need to rethink how we manage TTW utilities.)

  >>> print http(r"""
  ... GET /++etc++site/AddISearchableAuthenticationPluginTool HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Referer: http://localhost:8081/++etc++site/@@manageISearchableAuthenticationPluginTool.html
  ... """)
  HTTP/1.1 200 Ok
  ...

  >>> print http(r"""
  ... POST /++etc++site/AddISearchableAuthenticationPluginTool/AddPrincipalFolder.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------190685539214643056941988788830
  ... Referer: http://localhost:8081/++etc++site/AddISearchableAuthenticationPluginTool/AddPrincipalFolder.html=
  ... 
  ... -----------------------------190685539214643056941988788830
  ... Content-Disposition: form-data; name="field.prefix"
  ... 
  ... users.
  ... -----------------------------190685539214643056941988788830
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------190685539214643056941988788830
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... users
  ... -----------------------------190685539214643056941988788830--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: ../@@manageISearchableAuthenticationPluginTool.html
  ...

Next we'l add some users:

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------62010169718836874861388307181
  ... 
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... bob
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Bob
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------62010169718836874861388307181
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------62010169718836874861388307181--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------1501629520183211901834390790
  ... 
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... bill
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Bill
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------1501629520183211901834390790
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------1501629520183211901834390790--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------3362827831346173768318792608
  ... 
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... betty
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Betty
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------3362827831346173768318792608
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------3362827831346173768318792608--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------1771586876978613244952985501
  ... 
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... sally
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Sally
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------1771586876978613244952985501
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------1771586876978613244952985501--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------6406512534224572322062554722
  ... 
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... george
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... George
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------6406512534224572322062554722
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------6406512534224572322062554722--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------1596878616204415667781266350
  ... 
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... mike
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Mike
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------1596878616204415667781266350
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------1596878616204415667781266350--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

  >>> print http(r"""
  ... POST /++etc++site/tools/users/+/AddPrincipalInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------160587971417390263241080578782
  ... 
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="field.login"
  ... 
  ... mary
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="field.password"
  ... 
  ... 123
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Mary
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------160587971417390263241080578782
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------160587971417390263241080578782--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/users/@@contents.html
  ...

Next, we'll add out groups folder:

  >>> print http(r"""
  ... POST /++etc++site/AddIPrincipalSearchPluginTool/AddGroupFolder.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------18984415031531709165482618952
  ... 
  ... -----------------------------18984415031531709165482618952
  ... Content-Disposition: form-data; name="field.prefix"
  ... 
  ... groups.
  ... -----------------------------18984415031531709165482618952
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------18984415031531709165482618952
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... groups
  ... -----------------------------18984415031531709165482618952--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: ../@@manageIPrincipalSearchPluginTool.html
  ...

Now, before we can define any groups, we have to add and register a
pluggable authentication utility:

  >>> print http(r"""
  ... POST /++etc++site/default/@@contents.html HTTP/1.1
  ... Authorization: Basic bWdyOm1ncnB3
  ... Content-Type: application/x-www-form-urlencoded
  ... Referer: http://localhost:8081/++etc++site/default/@@contents.html
  ... 
  ... type_name=BrowserAdd__zope.app.authentication.authentication.LocalPluggableAuthentication&new_value=""")
  HTTP/1.1 303 See Other
  ...

  >>> print http(r"""
  ... POST /++etc++site/default/LocalPluggableAuthentication/addRegistration.html HTTP/1.1
  ... Authorization: Basic bWdyOm1ncnB3
  ... Content-Type: multipart/form-data; boundary=---------------------------1649392783947785437368129046
  ... Referer: http://localhost:8081/++etc++site/default/LocalPluggableAuthentication/
  ... 
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="field.name"
  ... 
  ... 
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="field.interface"
  ... 
  ... zope.app.security.interfaces.IAuthentication
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="field.interface-empty-marker"
  ... 
  ... 1
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="field.permission"
  ... 
  ... 
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="field.permission-empty-marker"
  ... 
  ... 1
  ... -----------------------------1649392783947785437368129046
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------1649392783947785437368129046--
  ... """)
  HTTP/1.1 303 See Other
  ...


and configure it to use the principal folder and the groups folder:


  >>> print http(r"""
  ... POST /++etc++site/default/LocalPluggableAuthentication/@@edit.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------18023914511159666166636904990
  ... 
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.extractors.to"
  ... 
  ... HTTP Basic
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.authenticators.to"
  ... 
  ... users
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.challengers.to"
  ... 
  ... No Challenge if Authenticated
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.challengers.to"
  ... 
  ... Zope Realm HTTP Basic
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.factories.to"
  ... 
  ... Default
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.searchers.to"
  ... 
  ... users
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.searchers.to"
  ... 
  ... groups
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.extractors"
  ... 
  ... HTTP Basic
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.authenticators"
  ... 
  ... users
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.challengers"
  ... 
  ... No Challenge if Authenticated
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.challengers"
  ... 
  ... Zope Realm HTTP Basic
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.factories"
  ... 
  ... Default
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.searchers"
  ... 
  ... users
  ... -----------------------------18023914511159666166636904990
  ... Content-Disposition: form-data; name="field.searchers"
  ... 
  ... groups
  ... -----------------------------18023914511159666166636904990--
  ... """)
  HTTP/1.1 200 Ok
  ...

Now, we can define some groups.  Let's start with a group named
"Admin":

  >>> print http(r"""
  ... POST /++etc++site/tools/groups/+/AddGroupInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------5412502961004181070544094984
  ... 
  ... -----------------------------5412502961004181070544094984
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Admin
  ... -----------------------------5412502961004181070544094984
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------5412502961004181070544094984
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------5412502961004181070544094984
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------5412502961004181070544094984--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/groups/@@contents.html
  ...

That includes Betty, Mary and Mike:

  >>> print http(r"""
  ... POST /++etc++site/tools/groups/1/@@edit.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------67523504021030130962010243745
  ... Referer: http://localhost:8081/++etc++site/tools/groups/1/@@edit.html
  ... 
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Admin
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuMw__
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuNw__
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuNg__
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals.displayed"
  ... 
  ... y
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals.MC51c2Vycw__.query.field.search"
  ... 
  ... 
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals.MC5ncm91cHM_.query.field.search"
  ... 
  ... 
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="field.principals.MA__.query.searchstring"
  ... 
  ... 
  ... -----------------------------67523504021030130962010243745
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------67523504021030130962010243745--
  ... """)
  HTTP/1.1 200 Ok
  ...

and a group "Power Users":

  >>> print http(r"""
  ... POST /++etc++site/tools/groups/+/AddGroupInformation.html%3D HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------14430301351028860873795053640
  ... 
  ... -----------------------------14430301351028860873795053640
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Power Users
  ... -----------------------------14430301351028860873795053640
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------14430301351028860873795053640
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------14430301351028860873795053640
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... power
  ... -----------------------------14430301351028860873795053640--
  ... """)
  HTTP/1.1 303 See Other
  ...
  Location: http://localhost/++etc++site/tools/groups/@@contents.html
  ...

with users Betty, Bill, Bob, George, and Mary:

  >>> print http(r"""
  ... POST /++etc++site/tools/groups/power/@@edit.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Type: multipart/form-data; boundary=---------------------------46600477014278930691159535998
  ... 
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... Power Users
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuMw__
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuMg__
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuMQ__
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuNQ__
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals:list"
  ... 
  ... dXNlcnMuNw__
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals.displayed"
  ... 
  ... y
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals.MC51c2Vycw__.query.field.search"
  ... 
  ... 
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals.MC5ncm91cHM_.query.field.search"
  ... 
  ... 
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="field.principals.MA__.query.searchstring"
  ... 
  ... 
  ... -----------------------------46600477014278930691159535998
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------46600477014278930691159535998--
  ... """)
  HTTP/1.1 200 Ok
  ...

Now, with these groups set up, we should see these groups on the
affected principals.  First, we'll make the root folder the
thread-local site:

  >>> from zope.app.component.hooks import setSite
  >>> setSite(getRootFolder())

and we'll get the pluggable authentication utility:

  >>> from zope.app import zapi
  >>> principals = zapi.principals()

Finally we'll get Betty and see that she is in the admin and
power-user groups:

  >>> betty = principals.getPrincipal(u'users.3')
  >>> betty.groups.sort()
  >>> betty.groups
  [u'groups.1', u'groups.power']

And we'll get Bill, and see that he is only in the power-user group:

  >>> bill = principals.getPrincipal(u'users.2')
  >>> bill.groups
  [u'groups.power']
