================ Principal Folder ================ 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 then in map fashion to a principal folder: >>> from zope.app.authentication.principalfolder import PrincipalFolder >>> principals = PrincipalFolder('principal.') >>> principals['p1'] = p1 >>> principals['p2'] = p2 Authentication -------------- 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) Search ------ 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'] Changing credentials -------------------- 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') Removing principals ------------------- Of course, if a principal is removed, we can no-longer authenticate it: >>> del principals['p1'] >>> principals.authenticateCredentials({'login': 'bob', ... 'password': 'eek'})