Principal folders contain principal-information objects that contain principal information. We create an internal principal using the InternalPrincipal class:
>>> from zope.app.authentication.principalfolder import InternalPrincipal >>> p1 = InternalPrincipal('login1', '123', "Principal 1", ... passwordManagerName="SHA1") >>> p2 = InternalPrincipal('login2', '456', "The Other One")
and add them to a principal folder:
>>> from zope.app.authentication.principalfolder import PrincipalFolder >>> principals = PrincipalFolder('principal.') >>> principals['p1'] = p1 >>> principals['p2'] = p2
Principal folders provide the IAuthenticatorPlugin interface. When we provide suitable credentials:
>>> from zope.testing.doctestunit import pprint >>> principals.authenticateCredentials({'login': 'login1', 'password': '123'}) PrincipalInfo(u'principal.p1')
We get back a principal id and supplementary information, including the principal title and description. Note that the principal id is a concatenation of the principal-folder prefix and the name of the principal-information object within the folder.
None is returned if the credentials are invalid:
>>> principals.authenticateCredentials({'login': 'login1', ... 'password': '1234'}) >>> principals.authenticateCredentials(42)
Principal folders also provide the IQuerySchemaSearch interface. This supports both finding principal information based on their ids:
>>> principals.principalInfo('principal.p1') PrincipalInfo('principal.p1')>>> principals.principalInfo('p1')
and searching for principals based on a search string:
>>> list(principals.search({'search': 'other'})) [u'principal.p2']>>> list(principals.search({'search': 'OTHER'})) [u'principal.p2']>>> list(principals.search({'search': ''})) [u'principal.p1', u'principal.p2']>>> list(principals.search({'search': 'eek'})) []>>> list(principals.search({})) []
If there are a large number of matches:
>>> for i in range(20): ... i = str(i) ... p = InternalPrincipal('l'+i, i, "Dude "+i) ... principals[i] = p>>> pprint(list(principals.search({'search': 'D'}))) [u'principal.0', u'principal.1', u'principal.10', u'principal.11', u'principal.12', u'principal.13', u'principal.14', u'principal.15', u'principal.16', u'principal.17', u'principal.18', u'principal.19', u'principal.2', u'principal.3', u'principal.4', u'principal.5', u'principal.6', u'principal.7', u'principal.8', u'principal.9']
We can use batching parameters to specify a subset of results:
>>> pprint(list(principals.search({'search': 'D'}, start=17))) [u'principal.7', u'principal.8', u'principal.9']>>> pprint(list(principals.search({'search': 'D'}, batch_size=5))) [u'principal.0', u'principal.1', u'principal.10', u'principal.11', u'principal.12']>>> pprint(list(principals.search({'search': 'D'}, start=5, batch_size=5))) [u'principal.13', u'principal.14', u'principal.15', u'principal.16', u'principal.17']
There is an additional method that allows requesting the principal id associated with a login id. The method raises KeyError when there is no associated principal:
>>> principals.getIdByLogin("not-there") Traceback (most recent call last): KeyError: 'not-there'
If there is a matching principal, the id is returned:
>>> principals.getIdByLogin("login1") u'principal.p1'
Credentials can be changed by modifying principal-information objects:
>>> p1.login = 'bob' >>> p1.password = 'eek'>>> principals.authenticateCredentials({'login': 'bob', 'password': 'eek'}) PrincipalInfo(u'principal.p1')>>> principals.authenticateCredentials({'login': 'login1', ... 'password': 'eek'})>>> principals.authenticateCredentials({'login': 'bob', ... 'password': '123'})
It is an error to try to pick a login name that is already taken:
>>> p1.login = 'login2' Traceback (most recent call last): ... ValueError: Principal Login already taken!
If such an attempt is made, the data are unchanged:
>>> principals.authenticateCredentials({'login': 'bob', 'password': 'eek'}) PrincipalInfo(u'principal.p1')
Of course, if a principal is removed, we can no-longer authenticate it:
>>> del principals['p1'] >>> principals.authenticateCredentials({'login': 'bob', ... 'password': 'eek'})