Using Principal Folders
=======================

Principal folders are Pluggable-Authentication plugins that manage
principal information, especially authentication credentials.  To use
a principal folder, you need to create a principal folder in a site
management folder and then configure it in a plugins authentication.
Let's look at an example, in which we'll define a new manager named
Bob.  Initially, attempts to log in as Bob fail:

  >>> print http(r"""
  ... GET /manage HTTP/1.1
  ... Authorization: Basic Ym9iOjEyMw==
  ... """)
  HTTP/1.1 401 Unauthorized
  ...

To allow Bob to log in, we'll start by adding a principal folder:


(The following 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-Length: 434
  ... 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
  ...

We specify a prefix, `users.`.  This is used to make sure that ids
used by this plugin don't conflict with ids of other plugins.  We also
name ths plugin `users`.  This is the name we'll use when we configure
the pluggable authentiaction service.

Next we'll view the contents page of the principal folder:

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

And we'll add a principal, Bob:

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

Note that we didn't pick a name.  The name, together with the folder
prefix. If we don't choose a name, a numeric id is chosen.

Now we have a principal folder with a principal. We need to create 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:

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

We also tell it:

  - to use HTTP Basic authentication with the Zope realm,

  - not to challenge authenticated principals, and

  - to use the default principal factory

Now, with this in place, Bob can log in, but he isn't allowed to
access the management interface:


  >>> print http(r"""
  ... GET /manage HTTP/1.1
  ... Authorization: Basic Ym9iOjEyMw==
  ... """)
  HTTP/1.1 403 Forbidden
  ...

We go to the granting interface and search for and find a principal named Bob:

  >>> print http(r"""
  ... POST /@@grant.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Length: 226
  ... Content-Type: application/x-www-form-urlencoded
  ... Referer: http://localhost:8081/@@grant.html
  ... 
  ... field.principal.displayed=y&field.principal.MC51c2Vycw__.query.field.search=&field.principal.MC51c2Vycw__.query.search=Search&field.principal.MA__.query.searchstring=&field.principal.MA__.selection=em9wZS5zYW1wbGVfbWFuYWdlcg__""")
  HTTP/1.1 200 Ok
  ...
  <select name="field.principal.MC51c2Vycw__.selection">
  <option value="dXNlcnMuMQ__">Bob</option>
  </select>
  ...

We select Bob and grant him the Manager role:

  >>> print http(r"""
  ... POST /@@grant.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Length: 5316
  ... Content-Type: application/x-www-form-urlencoded
  ... Referer: http://localhost:8081/@@grant.html
  ... 
  ... field.principal=dXNlcnMuMQ__"""
  ... """&field.principal.displayed=y"""
  ... """&field.principal.MC51c2Vycw__.query.field.search=bob"""
  ... """&field.principal.MA__.query.searchstring="""
  ... """&GRANT_SUBMIT=Change"""
  ... """&field.dXNlcnMuMQ__.role.zope.Manager=allow"""
  ... """&field.dXNlcnMuMQ__.role.zope.Manager-empty-marker=1""")
  HTTP/1.1 200 Ok
  ...

At which point, Bob can access the management interface:

  >>> print http(r"""
  ... GET /@@contents.html HTTP/1.1
  ... Authorization: Basic Ym9iOjEyMw==
  ... """)
  HTTP/1.1 200 Ok
  ...
