flask_open_directory package¶
Subpackages¶
Submodules¶
flask_open_directory.decorators module¶
-
class
flask_open_directory.decorators.DecoratorContext[source]¶ Bases:
dictA specialized dict, used in request decorators. The keys are accessible using normal dict style or with attribute (dot) style syntax.
-
flask_open_directory.decorators.pass_context(fn)[source]¶ Helper that passes a
DecoratorContexwith theOpenDirectoryregistered with the current application and theusernamefor the request. This will pass thecontextas the first arg to the decorator.See also
-
flask_open_directory.decorators.requires_all_groups(*group_names)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of all the passed in groups.
This is similar to the
requires_group, only it accepts multiple groups to check against.Parameters: group_names – The group name(s) to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_all_groups app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' open_directory = OpenDirectory(app) @app.route('/office-admins') @requires_all_groups('administrators', 'office') def office_admins(): return "Hello, '{}'. You are an office administrator".format( utils.username_from_request() )
-
flask_open_directory.decorators.requires_any_group(*group_names)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of any of the passed in groups.
This is similar to the
requires_all_groups, only it accepts multiple groups to check against, and succeeds if the authenticated user is a member of any of the specified groups.Parameters: group_names – The group name(s) to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_any_group app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' open_directory = OpenDirectory(app) @app.route('/office-or-admins') @requires_any_group('administrators', 'office') def office_or_admins(): return "Hello, '{}'. You're an administrator or office user".format( utils.username_from_request() )
-
flask_open_directory.decorators.requires_group(group_name)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of the specified group.
Parameters: group_name – The group name to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_group app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' od = OpenDirectory(app) ... other routes @app.route('/admins') @requires_group('administrators') def admins_only(): return "Hello, '{}'. You are an administrator".format( utils.username_from_request() )
flask_open_directory.open_directory module¶
-
class
flask_open_directory.open_directory.OpenDirectory(app=None)[source]¶ Bases:
flask_open_directory.base.BaseOpenDirectory-
init_app(app)[source]¶ Initialize the extension with the application.
Parameters: app – The flask.Flaskapplication to register the extension with.
-
flask_open_directory.utils module¶
-
flask_open_directory.utils.base_dn_from_url(url)[source]¶ Split a url into a base_dn.
Parameters: url (
str) – A url string.Example: >>> base_dn_from_url('open_directory.local') 'dc=open_directory,dc=local' >>> base_dn_from_url('api.open_directory.com') 'dc=api,dc=open_directory,dc=com'
Return type: str
Module contents¶
-
class
flask_open_directory.OpenDirectoryABC[source]¶ Bases:
objectThis
abchas all the methods that should be implemented for an object to be considered a validOpenDirectorysubclass.All of the methods must be implemented to create a subclass, or to pass an
isinstanceorissubclasscheck.-
base_dn¶ Return the base ldap domain. Used to build ldap queries.
Return type: str
-
connection¶ An
ldap3.Connectionused for queries. This should only return a connection if there is a flask application running with the connection stored on it.Return type: Optional[Connection]
-
connection_ctx()[source]¶ A context manager to yield an
ldap3.Connection, this should try to create a connection regardless of if a flask application is running.Return type: ContextManager[]
-
server_url¶ Return the ldap server url. Used for the ldap connection.
Return type: str
-
-
class
flask_open_directory.BaseOpenDirectory(**config)[source]¶ Bases:
flask_open_directory.base.open_directory_abc.OpenDirectoryABCImplements the
OpenDirectoryABC.This stores all kwargs into a
configattribute, which is used to get the server url and an optional base dn.-
base_dn¶ Return the base dn for the open directory server. This looks in the
configdict for key ‘OPEN_DIRECTORY_BASE_DN’ and if nothing is found it will create one from theserver_url.Note
If your server url is an ip address, then you need to set this in the config.
Return type: str
-
connect()[source]¶ Create’s an
ldap3.Connection, that will need to be managed by the caller (closed, cleanup, etc). This is primarily used when there is a flask application running. It is better to use theconnection_ctxcontext manager.Return type: Connection
-
connection¶ Return’s a shared connection when a flask application is running. If there is not flask application running, then this property will return
None.If you need a connection outside of a flask application context, then you can create one with the
connectmethod or use theconnection_ctxmethod, which works the same with or without an application context.Return type: Union[None,Connection]
-
connection_ctx()[source]¶ A context manager that will use the shared connection if a flask application context is available if not it will create a connection for running one-off commands.
Return type: ContextManager[]
-
create_server()[source]¶ Create’s a
ldap3.Serverwith this instancesserver_url. This method is typically only used internally.Return type: Server
-
server_url¶ Return the server url for an instance. This looks in the
configdict for key ‘OPEN_DIRECTORY_SERVER’ and if noting is found it returns_default_serverset on the class (default ‘localhost’).Return type: str
-
-
class
flask_open_directory.OpenDirectory(app=None)[source]¶ Bases:
flask_open_directory.base.BaseOpenDirectory-
init_app(app)[source]¶ Initialize the extension with the application.
Parameters: app – The flask.Flaskapplication to register the extension with.
-
-
class
flask_open_directory.Query(open_directory=None, model=None, search_base=None, search_filter=None, connection=None, ldap_attributes=None)[source]¶ Bases:
flask_open_directory.query.base_query.BaseQueryExtends the
BaseQuerywith some helper methods. The helpers typically return the query when called for method chaining.This allows a query to be mostly setup by another object, and the caller provide the criteria for the search.
Example:
>>> query = Query(open_directory=OpenDirectory()) >>> query(User).filter(username='testuser').first() User(...) >>> query.all() # reuse the same criteria, only get all the users [User(...), ...] >>> q = query(Group) # change the ``model`` on a query >>> q == query True >>> q.filter(group_name='testgroup').first() Group(...)
-
filter(*args, **kwargs)[source]¶ Set’s the search filter for an instance, returning the query for method chaining.
This method will accept a string or keyword arguments as parameters.
If there is a string passed in it is set as the filter on the instance. There is no parsing or validation done on a string if it’s passed in, which can cause errors when performing the query if it is an invalid filter string.
If there is no string passed in then keyword arguments are parsed with the current
modelset on an instance. This means that you can build a query using either the model’s attribute name or the ldap entry key.Example: >>> from open_directory_utils.model import User >>> from open_directory_utils.query import Query >>> q = Query(search_base='dc=example,dc=com', model=User) >>> q.filter(username='testuser') Query(...) >>> print(q.search_filter) '(uid=testuser)' >>> q.filter(uid='anotheruser') Query(...) >>> print(q.search_filter) '(uid=anotheruser)' >>> q.filter('(cn='Test User')') >>> print(q.search_filter) '(cn=Test User)'
Return type:
-
-
class
flask_open_directory.BaseQuery(open_directory=None, model=None, search_base=None, search_filter=None, connection=None, ldap_attributes=None)[source]¶ Bases:
flask_open_directory.query.query_abc.QueryABCImplementation of
QueryABCabstract class. This is used to search an ldap connection and convert the entries into aModelABCsubclass.This also adds a helpful context manager
BaseQuery.connection_ctx(), which is helpful if you do not have a flask application running, it will try to create a connection with theopen_directoryset on the instance for the search.-
all(connection=None, convert=True)[source]¶ Query the connection and return a tuple of all items found for the current state of the query. This will return an empty tuple if a connection was not established or there was no entries to match the filter criteria.
Parameters: - connection (
Optional[Connection]) – An optionalldap3.Connectionto use for the search. - convert – Whether to convert the
ldap3.Entry‘s to themodelset on a class. Default isTrue
Return type: Tuple[Any]- connection (
-
connection¶ An
ldap3.Connectionfor the query. If this is not set explicitly, then we will see if anopen_directoryis set on the instance and return it’sconnection, which could still beNone, if there is no flask application running.If you don’t know wheter you are working inside of the application context or not, then it is safer to use the
BaseQuery.connection_ctx()method.Raises: TypeError – If explicitly setting this to something other than an ldap3.Connection.Return type: ContextManager[]
-
connection_ctx()[source]¶ A context manager that tries to find a connection to use. If a connection is found on the instance or the
open_directoryof an instance, then that will be used. If not it will try to create one using an instancesopen_directory.If a connection is not able to be found this will yield
None, so you should check before using the connection.Example:
>>> with query.connection_ctx() as conn: ... model = query.first(conn)
Return type: Optional[Connection]
-
first(connection=None, convert=True)[source]¶ Query the connection and return the first item found for the current state of the query. This will return
Noneif a connection was not established or there was no entry to match the filter criteria.Parameters: - connection (
Optional[Connection]) – An optionalldap3.Connectionto use for the search. - convert – Whether to convert the
ldap3.Entryto themodelset on a class. Default isTrue
Return type: Any- connection (
-
ldap_attributes¶ The ldap attributes to return with the query. These should be a list/tuple of strings that are attributes in the ldap database.
If none have been set explicitly on an instance, then we will check if there is a
model, and use it’sldap_keysfor this value.Return type: Union[None,Iterable[str]]
-
model¶ A
ModelABCsubclass used for search criterea and to in converting returned entries into the desired model.The attribute can be set with either a class or an instance of a class, but we always store a reference to the class.
Return type: Any
-
open_directory¶ A
OpenDirectoryABCsubclass used for the connection for the query.Return type: Any
-
search_base¶ A string representing where to search.
This property will try to derive this value from several places. If it set explicitly, then that will be the preferred return value.
If it is not set explicitly, then we will check if there is an
OpenDirectoryset for the instance. If so we will use thebase_dnproperty from theopen_directory. We will further check if amodelhas been set for the instance and we will add it’squery_cn.Return type: Optional[str]
-
search_filter¶ The ldap filter string for the query. If not set then we will return the class’s
_default_search_filterwhich is ‘(objectClass=*)’Return type: str
-
-
class
flask_open_directory.QueryABC[source]¶ Bases:
objectThis
abchas all the methods that should be implemented for an object to be considered a validQuerysubclass.All of the methods must be implemented to create a subclass, or to pass an
isinstanceorissubclasscheck.-
all(connection=None)[source]¶ Searches the ldap connection returning tuple of all the entries found. Or an empty tuple.
Parameters: connection ( Optional[Connection]) – An optional connection to use for the search.Return type: Tuple[Any]
-
connection¶ Return the ldap connection for the query.
Return type: Union[None,Connection]
-
first(connection=None)[source]¶ Searches the ldap connection returning the first entry, if any are found or
Noneif not.Parameters: connection ( Optional[Connection]) – An optional connection to use for the search.Return type: Any
-
ldap_attributes¶ Return the ldap attributes to return for the query.
Return type: Iterable[str]
-
search_base¶ Return the ldap serach base dn string for the query.
Return type: str
-
search_filter¶ Return the ldap search filter string for the query.
Return type: str
-
-
class
flask_open_directory.User(**kwargs)[source]¶ Bases:
flask_open_directory.model.model.BaseModelRepresents a user in the open directory
See also
BaseModelfor inherited methods.-
email= Attribute('mail', allow_multiple=True)¶
-
full_name= Attribute('cn', allow_multiple=False)¶
-
id= Attribute('apple-generateduid', allow_multiple=False)¶
-
username= Attribute('uid', allow_multiple=False)¶
-
-
class
flask_open_directory.Group(**kwargs)[source]¶ Bases:
flask_open_directory.model.model.BaseModelRepresents a group in the open directory
See also
BaseModelfor inherited methods.-
full_name= Attribute('apple-group-realname', allow_multiple=False)¶
-
group_name= Attribute('cn', allow_multiple=False)¶
-
has_user(user)[source]¶ Check if a user is part of the group.
Parameters: user ( str) – Either the username (uid) or id (apple-generateduid) of a user.Return type: bool
-
id= Attribute('apple-generateduid', allow_multiple=False)¶
-
member_ids= Attribute('apple-group-memberguid', allow_multiple=True)¶
-
users= Attribute('memberUid', allow_multiple=True)¶
-
-
class
flask_open_directory.BaseModel(**kwargs)[source]¶ Bases:
flask_open_directory.model.model_abc.ModelABCImplementation of
ModelABC. Used to map ldap entry keys to python attributes.Parameters: kwargs – Values to set for the attributes of an instance. These can be passed in with the python attribute name as the key or the ldap entry name as the key and the values will be stored and accessible appropriately.
Example: >>> class User(BaseModel): ... id = Attribute('apple-generateduid') >>> user = User(id='123') >>> user.id == '123' True >>> user2 = User(**{'apple-generateduid': '456'}) >>> user2.id == '456' True
-
classmethod
attribute_for_key(key)[source]¶ Return
Attributefor the given key, which can be the python attribute or the ldap entry key.Returns
Noneif not foundReturn type: Optional[Attribute]
-
classmethod
-
class
flask_open_directory.Attribute(ldap_key, allow_multiple=False)[source]¶ Bases:
objectRepresents an LDAP entry attribute. It maps the ldap entry key to an attribute on a Model.
Parameters: - ldap_key – The ldap entry key for the attribute.
- allow_multiple – If
False(default) then any lists only return the first item. IfTruereturn the whole list of values.
-
class
flask_open_directory.ModelABC[source]¶ Bases:
objectAn abstract class with some default implementations for a model, which maps the
OpenDirectory (ldap attributes)to a python object.Any of the methods that have a default implementation can be accessed on a derived subclass via the
supermechanism.-
classmethod
attribute_name_for(ldap_key)[source]¶ Retrieve the python model object’s attribute name for a given ldap entry key.
This default implementation checks the
ldap_attribute_map(), returning,keyfor thevaluein the mapping, orNoneif not found.You can use the default implementation from the
supermechanism in your subclass.Parameters: ldap_key ( str) – The ldap entry key.Return type: Union[None,str]
-
classmethod
from_entry(entry)[source]¶ Return an instance of the class from an
ldap3.EntryThe default implementation requires that a subclass accepts
kwargsfor all attributes in it’s__init__method.Parameters: entry ( Entry) – Anldap3.Entryto convert to this python model.Return type: An instance of the python model.
-
classmethod
ldap_attribute_map()[source]¶ Return a mapping of <model attribute: ldap key> values.
This does not have a default implementation, and must be implemented on the subclass.
Return type: Dict[str,str]
-
classmethod
ldap_keys()[source]¶ Return all the ldap keys
This default implementation returns the
valuesfrom theldap_attribute_map().You can use the default implementation from the
supermechanism in your subclass.Return type: Tuple[str]
-
classmethod
query_cn()[source]¶ Return the query cn to be used in queries. This value will get added to the
base_dnas ‘cn=<this value>,<base_dn>’ for queries.The default implementation returns the lower case version of the class name and appends an ‘s’.
You can use the default implementation from the
supermechanism in your subclass.Example:
# given a base dn of 'dc=example,dc=com' >>> class User(ModelABC): pass >>> open_directory = OpenDirectory() >>> query = Query(open_directory=open_directory, model=User) >>> query.search_base 'cn=users,dc=example,dc=com'
Return type: str
-
classmethod
-
flask_open_directory.requires_group(group_name)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of the specified group.
Parameters: group_name – The group name to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_group app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' od = OpenDirectory(app) ... other routes @app.route('/admins') @requires_group('administrators') def admins_only(): return "Hello, '{}'. You are an administrator".format( utils.username_from_request() )
-
class
flask_open_directory.DecoratorContext[source]¶ Bases:
dictA specialized dict, used in request decorators. The keys are accessible using normal dict style or with attribute (dot) style syntax.
-
flask_open_directory.pass_context(fn)[source]¶ Helper that passes a
DecoratorContexwith theOpenDirectoryregistered with the current application and theusernamefor the request. This will pass thecontextas the first arg to the decorator.See also
-
flask_open_directory.requires_any_group(*group_names)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of any of the passed in groups.
This is similar to the
requires_all_groups, only it accepts multiple groups to check against, and succeeds if the authenticated user is a member of any of the specified groups.Parameters: group_names – The group name(s) to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_any_group app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' open_directory = OpenDirectory(app) @app.route('/office-or-admins') @requires_any_group('administrators', 'office') def office_or_admins(): return "Hello, '{}'. You're an administrator or office user".format( utils.username_from_request() )
-
flask_open_directory.requires_all_groups(*group_names)[source]¶ Decorator to mark a flask route as requiring the authenticated user to be apart of all the passed in groups.
This is similar to the
requires_group, only it accepts multiple groups to check against.Parameters: group_names – The group name(s) to query the open_directory connection for and is required that the username (retrieved from Authorizationheader in the request) is apart of the given group. If the user is not then we abort with a401code.Example:
# app.py from flask import Flask from open_directory_utils import OpenDirectory, utils, requires_all_groups app = Flask(__name__) app.config['OPEN_DIRECTORY_SERVER'] = 'example.com' open_directory = OpenDirectory(app) @app.route('/office-admins') @requires_all_groups('administrators', 'office') def office_admins(): return "Hello, '{}'. You are an office administrator".format( utils.username_from_request() )