Difference between revisions of "Authentication"

From GNU MediaGoblin Wiki
Jump to navigation Jump to search
(→‎Auth Plugin Design Pros/Cons: More Pros/Cons; sone code fixups)
Line 15: Line 15:
 
_auth_providers.append(provider)
 
_auth_providers.append(provider)
   
def get_response(function(*args)):
+
def get_response(function, *args):
for p in _auth_providers:
+
for p in _auth_providers:
response = p.function(*args)
+
response = p.function(*args)
 
class AuthUserInterface(object):
 
 
def check_login(self, user, password):
 
response = get_response(check_login(user, password))
 
 
if response:
 
if response:
 
return response
 
return response
raise NotImplementedError</nowiki>
+
raise NotImplemented("No provider for %s" % functions)
  +
 
def check_login(self, user, password):
 
return get_response("check_login", user, password)
   
 
auth_plugin/__init__.py:<nowiki>
 
auth_plugin/__init__.py:<nowiki>
 
def setup_plugin():
 
def setup_plugin():
add_auth_provider(AuthPluginInterface())</nowiki>
+
add_auth_provider(SomeAuthPlugin(config1))
  +
add_auth_provider(SomeAuthPlugin(config2))</nowiki>
   
 
====Pros====
 
====Pros====
  +
* Plugins could inherit from another plugin and override.
  +
* Plugins can configure the individual instance (ldap server name)
  +
* Plugins can instantiate multiple providers for different backends, like two different ldap servers
   
 
====Cons====
 
====Cons====
Line 39: Line 41:
 
===Interfacey Design w/ hooks:===
 
===Interfacey Design w/ hooks:===
   
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface.
+
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more "hooky".
   
 
Ex:
 
Ex:
 
auth/__init__.py:<nowiki>
 
auth/__init__.py:<nowiki>
  +
...
 
def setup_auth():
 
def setup_auth():
 
global _auth_providers
 
global _auth_providers
_auth_providers = hook_runall("auth_provider")
+
_auth_providers += hook_runall("auth_provider")
  +
...
 
def get_response(function(*args)):
 
for p in _auth_providers:
 
response = p.function(*args)
 
 
class AuthUserInterface(object):
 
 
def check_login(self, user, password):
 
response = get_response(check_login(user, password))
 
if response:
 
return response
 
raise NotImplementedError</nowiki>
 
   
 
auth_plugin/__init__.py:<nowiki>
 
auth_plugin/__init__.py:<nowiki>
hooks = {"auth_provider": AuthUserInterface()}</nowiki>
+
hooks = {"auth_provider": get_auth_provider}
  +
def get_auth_provider(): return AuthUserInterface()</nowiki>
   
 
====Pros====
 
====Pros====
  +
* Plugins could inherit from another plugin and override.
  +
* Still allows configuration on the individual instance
   
 
====Cons====
 
====Cons====
 
 
* would basically be duplicating the code for hook_handle
 
* would basically be duplicating the code for hook_handle
  +
* No easy way to add multiple instances of one Provider
   
 
===Non-Interfacey Design w/ hooks for every call:===
 
===Non-Interfacey Design w/ hooks for every call:===
Line 78: Line 73:
   
 
auth_plugin/__init__.py:<nowiki>
 
auth_plugin/__init__.py:<nowiki>
hooks = {"auth_check_login": check_login</nowiki>
+
hooks = {"auth_check_login": check_login}
 
def check_login(user, password):
  +
if a: return True # Yes, let them in
  +
if b: return False # No and don't try other providers
  +
return None # Don't know, try next provider.</nowiki>
   
 
====Pros====
 
====Pros====
Line 85: Line 84:
   
 
====Cons====
 
====Cons====
  +
  +
All the Pros from the interface design are not here:
  +
* config data has to be global on the plugin, not local to the instantiated provider
  +
* No straight way of doing multiple instances.
  +
*: Yes, the individual hook could do it by itself
   
 
== __init__.py Base Class ==
 
== __init__.py Base Class ==

Revision as of 16:04, 2 May 2013

Designing Authentication API

To make our auth(entication) system more modular, we're likely going to have some sort of interface style API for it. This page is to design it.

Auth Plugin Design Pros/Cons

Interfacey Design w/o hooks:

Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.

Ex:

   auth/__init__.py:
        _auth_providers = []
        def add_auth_provider(provider):
            _auth_providers.append(provider)

        def get_response(function, *args):
            for p in _auth_providers:
                response = p.function(*args)
                if response:
                    return response
            raise NotImplemented("No provider for %s" % functions)

        def check_login(self, user, password):
            return get_response("check_login", user, password)

    auth_plugin/__init__.py:<nowiki>
        def setup_plugin():
            add_auth_provider(SomeAuthPlugin(config1))
            add_auth_provider(SomeAuthPlugin(config2))

Pros

  • Plugins could inherit from another plugin and override.
  • Plugins can configure the individual instance (ldap server name)
  • Plugins can instantiate multiple providers for different backends, like two different ldap servers

Cons

  • basically be duplicating the code for hook_handle

Interfacey Design w/ hooks:

Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more "hooky".

Ex:

   auth/__init__.py:
        ...
        def setup_auth():
            global _auth_providers
            _auth_providers += hook_runall("auth_provider")
        ...

    auth_plugin/__init__.py:<nowiki>
        hooks = {"auth_provider": get_auth_provider}
        def get_auth_provider(): return AuthUserInterface()

Pros

  • Plugins could inherit from another plugin and override.
  • Still allows configuration on the individual instance

Cons

  • would basically be duplicating the code for hook_handle
  • No easy way to add multiple instances of one Provider

Non-Interfacey Design w/ hooks for every call:

This design would have a plugin "template" in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.

Ex.
   auth/__init__.py:
        def check_login(user, Password):
            return hook_handle("auth_check_login", user, password)
   auth_plugin/__init__.py:
        hooks = {"auth_check_login": check_login}
        def check_login(user, password):
            if a: return True   # Yes, let them in
            if b: return False  # No and don't try other providers
            return None  # Don't know, try next provider.

Pros

  • Simpler to implement

Cons

All the Pros from the interface design are not here:

  • config data has to be global on the plugin, not local to the instantiated provider
  • No straight way of doing multiple instances.
    Yes, the individual hook could do it by itself

__init__.py Base Class

      • This is a brainstorm of some of the functions and variables that the base class should include.***

basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona

login_form = # Plugin LoginForm class

registration_form = # Plugin RegistrationForm class

   class UserAuthInterface(object):
       
        deg _raise_not_implemented(self):
            # Will raise a warning if some component of this interface isn't implemented by an Auth plugin

        def check_login(self, user, password):
            return False
        
        def get_user(self, *args):
            # Will query database and will return a User() object

        def create_user(self, *args):
            # Will create a new user and save to the db.
            # Will return User() object

        def extra_validation(self, register_form, *args):
            # Will query the db and add error messages to register_form if any.
            # return true if able to create new user 

        def get_user_metadata(self, user):
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms