A presentation given at Plone Conference 2013 in Brasilia. This presentation explains Plone's Pluggable Authentication System (PAS) and how to get started with writing your own PAS Plugin.
Vector Search -An Introduction in Oracle Database 23ai.pptx
How to get started with the Pluggable Authentication System
1. How to get started with
Matt Hamilton
The Pluggable
Authentication System
Plone Conference 2013 - Brasilia
2. Plone Conference 2013 - Brasilia
Who am I?
• Working with Plone/Zope since 1999
• Director at Netsight in the UK
• Worked on a number of projects doing
authentication over the years
7. Plone Conference 2013 - Brasilia
Architecture
• Uses the Zope Component Architecture
(ZCA) heavily
• Many interfaces, each defining an aspect of
the authentication process
• Each plugin can implement one or more
interfaces
8. Plone Conference 2013 - Brasilia
Anonymoususerfactory Plugins
Create anonymous users.
Authentication Plugins
Authentication plugins are responsible for validating credentials
generated by the Extraction Plugin.
Challenge Plugins
Challenge plugins initiate a challenge to the user to provide credentials.
Challenge_Protocol_Chooser Plugins
Challenge Protocol Chooser plugins decide what authorizationprotocol to
use for a given request type.
Reset Credentials Plugins
Credential clear plugins respond to a user logging out.
Update Credentials Plugins
Credential update plugins respond to the user changing credentials.
Extraction Plugins
Extraction plugins are responsible for extracting credentials from the
request.
Group_Enumeration Plugins
Enumeration plugins allow querying groups by ID.
Group_Introspection Plugins
Group Introspection provides listings of groups and membership
Group_Management Plugins
Group Management provides add/write/deletion of groups and member
management
Groups Plugins
Groups plugins determine the groups to which a user belongs.
Local_Roles Plugins
Defines Policy for getting Local Roles
Notcompetent Plugins
Not-Competent plugins check whether this user folder should not
authenticate the current request. These plugins are not used for a top
level user folder. They are typically used to prevent shaddowing of
authentications by higher level user folders.
Properties Plugins
Properties plugins generate property sheets for users.
Request_Type_Sniffer Plugins
Request Type Sniffer plugins detect the type of an incoming
request.
Role_Assigner Plugins
Role Assigner plugins allow the Pluggable Auth Service to
assign roles to principals.
Role_Enumeration Plugins
Enumeration plugins allow querying roles by ID.
Roles Plugins
Roles plugins determine the global roles which a user has.
Update Plugins
Update plugins allow the user or the application to update the
user's properties.
User_Adder Plugins
User Adder plugins allow the Pluggable Auth Service to create
users.
User_Enumeration Plugins
Enumeration plugins allow querying users by ID, and
searching for users who match particular criteria.
Userfactory Plugins
Create users.
User_Introspection Plugins
The User Introspection plugins allow the Pluggable Auth
Service to provide lists of users
User_Management Plugins
The User Management plugins allow the Pluggable Auth
Service to add/delete/modify users
Validation Plugins
Validation plugins specify allowable values for user properties
(e.g., minimum password length, allowed characters, etc.)
9. Plone Conference 2013 - Brasilia
Interfaces
class IExtractionPlugin( Interface ):
""" Extracts login name and credentials from a request.
"""
def extractCredentials( request ):
""" request -> {...}
o Return a mapping of any derived credentials.
o Return an empty mapping to indicate that the plugin found no
appropriate credentials.
"""
10. Plone Conference 2013 - Brasilia
Interfaces
class IAuthenticationPlugin( Interface ):
""" Map credentials to a user ID.
"""
def authenticateCredentials( credentials ):
""" credentials -> (userid, login)
o 'credentials' will be a mapping, as returned by IExtractionPlugin.
o Return a tuple consisting of user ID (which may be different
from the login name) and login
o If the credentials cannot be authenticated, return None.
"""
11. Plone Conference 2013 - Brasilia
Interfaces
class IPropertiesPlugin( Interface ):
""" Return a property set for a user.
"""
def getPropertiesForUser( user, request=None ):
""" user -> {}
o User will implement IPropertiedUser.
o Plugin should return a dictionary or an object providing
IPropertySheet.
o Plugin may scribble on the user, if needed (but must still
return a mapping, even if empty).
o May assign properties based on values in the REQUEST object, if
present
"""
12. Plone Conference 2013 - Brasilia
Interfaces
class IGroupsPlugin( Interface ):
""" Determine the groups to which a user belongs.
"""
def getGroupsForPrincipal( principal, request=None ):
""" principal -> ( group_1, ... group_N )
o Return a sequence of group names to which the principal
(either a user or another group) belongs.
o May assign groups based on values in the REQUEST object, if present
"""
13. Plone Conference 2013 - Brasilia
Plugins
• Plugins can be stacked in order you want
them to be used
17. Plone Conference 2013 - Brasilia
Worked Example
• netsight.aspxauthplugin
• Encrypts/Decrypts the .ASPXAUTH cookie
used by .NET applications
• Allows Plone to trust the auth of a .NET
application and vice-versa
• Simplified, ignoring some of the boiler plate
and crypto code
18. Plone Conference 2013 - Brasilia
def extractCredentials( self, request )
“””To extract the cookie from the browser”””
def authenticateCredentials( self,
credentials )
“””To decrypt the cookie and validate it is correct”””
def resetCredentials(self, request,
response)
“””To delete the cookie on logout”””
20. Plone Conference 2013 - Brasilia
security.declarePrivate( 'authenticateCredentials' )
def authenticateCredentials( self, credentials ):
request = self.REQUEST
response = request.RESPONSE
# We only authenticate when our challenge mechanism
# extracted the cookie
if credentials.get('plugin') != self.getId():
return None
cookie = credentials.get('cookie')
if not cookie:
return None
sig, data = self.decodeCookie(cookie)
21. Plone Conference 2013 - Brasilia
# check signature is valid
if not self.checkSignature(data,sig):
return None
# decrypt data
decryptedBytes = self.decryptData(data)
if not decryptedBytes:
return None
# unpack the values from the data
unpacked = self.unpackData(decryptedBytes)
if unpacked is None:
return None
start_time, end_time, username, version, persistent,
userdata, path = unpacked
# return the userid and login
return username, username