Omeka / LDAP Plugin Dev. - I have a question

103 views
Skip to first unread message

Michelle

unread,
Feb 4, 2011, 10:40:38 AM2/4/11
to Omeka Dev
Hi All,

I am a new member to the group and this is my first time posting.

I'm working on a Plugin which will allow users to log into Omeka via
LDAP.

I think I've figured out the filters and am using them where I can. I
also think I've figured out how to intercept the routes where I think
I will need to using Zend_Controller_Router_Routes to direct them to
the LDAP controller I am writing.

In my attempt to replace (re-route) the page that allows a user to
request a password reset I ran into an issue. The issue is the
"_adminWhitelist" in Admin.php. It limits the controllers/actions for
'admin' actions before a user is signed in. I wanted to route the
users/forgot-password request through my controller to my view - which
would show a message explaining that since LDAP is used for
authentication the password cannot be reset here.

I tried multiple avenues to work around this with no success including
attempting to unregister the Omeka_Controller_Plugin_Admin temporarily
for this specific action. (Duplicating your technique in
Upgrade.php). Unfortunately...I could not get it to work - maybe a
matter of timing or my coding.

What did work (but I don't think it is a good approach) was to create
a copy of the Omeka_Controller_Plugin_Admin class within my plugin
directory adding my controller name - ldap and action - forgot-
password to the whitelist. This seems to work - It allows me to route
the request through my controller without kicking me back to the login
page. Although I'm not sure, I don't think this is the best
approach. Can anyone provide any thoughts/suggestions on this issue?
Any thoughts on an alternative approach?

Thanks so much!
Michelle

Kris Kelly

unread,
Feb 4, 2011, 11:17:27 AM2/4/11
to omek...@googlegroups.com
Did you try tacking on a new route that matches 'users/forgot-password' and then having that route go to ldap/forgot-password?

Routes are matched in reverse order, so you should be able to add additional routes that match existing URLs in order to override the default routing.

Unfortunately there's no way to alter the admin whitelist without hacking it as you did, but hopefully that would not be necessary if what I suggested actually works.

Kris

> --
> You received this message because you are subscribed to the Google Groups "Omeka Dev" group.
> To post to this group, send email to omek...@googlegroups.com.
> To unsubscribe from this group, send email to omeka-dev+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/omeka-dev?hl=en.
>

Kris Kelly

unread,
Feb 4, 2011, 11:55:52 AM2/4/11
to omek...@googlegroups.com
You're absolutely right, it looks like Omeka_Controller_Plugin_Admin has pre-emptively hosed all attempts to alter the list of whitelisted actions.

We ought to fix this in upcoming versions so that plugins are able to filter that whitelist. Until then, I can't think of a solution except maybe a crazy hack in your plugin installer that would actually overwrite the forgot-password.php view script in the admin with your custom version of that file. Or you could keep the hacked version of Omeka_Controller_Plugin_Admin, but both ways are just as likely to break in future versions.

Maybe somebody else has a better solution?

Kris

On Feb 4, 2011, at 11:32 PM, Michelle wrote:

> Thanks so much for responding. I think I tried to do what you
> suggested. The problem is every request - in the admin folder gets
> routed through that plugin - Omeka_Controller_Plugin_Admin. It
> filters out any request (in admin) controller/action that is not on
> the whitelist and re-routes it to the login page. Maybe my attempt
> was not coded correctly (is this what you meant?):
>
> $route = new Zend_Controller_Router_Route(
> 'users/forgot-password',
> array(
> 'module' => 'ldap',
> 'controller' => 'ldap',
> 'action' => 'forgot-password'
> ));
>
> $router->addRoute('forgot', $route);
>
> ...since I'm attempting to call the ldap controller - which is not on
> the admin whitelist...the request is re-routed to the login page:
> $this->getRedirector()->goto('login', 'users', 'default'); (from
> Admin.php - line 97).
>
> thanks again!
> Michelle

John Flatness

unread,
Feb 4, 2011, 3:06:22 PM2/4/11
to omek...@googlegroups.com
We probably do want to let people filter that whitelist, there's
probably a few use cases even in addition to this one that could use
that kind of functionality.

As for making this work with the current version of Omeka, I believe the
admin whitelist only checks the controller and action names and not the
module, so the tactic you've tried to use here would probably work if
your controller in your plugin was called "users" and not "ldap".

-John

Jeremy Boggs

unread,
Feb 4, 2011, 3:22:53 PM2/4/11
to omek...@googlegroups.com
Seems like we could add this filter to one of next 1.x releases of
Omeka. I've added a ticket for it, but haven't associated the ticket to
a milestone yet.[1] Michelle, since you've already explored this problem
some, are you interested in working on this ticket, and submitting a patch?

Best,
Jeremy

[1] https://omeka.org/trac/ticket/1028

--
Jeremy Boggs · Associate Director of Research · Center for History and
New Media · George Mason University · chnm.gmu.edu · @clioweb

Michelle

unread,
Feb 7, 2011, 10:02:42 AM2/7/11
to Omeka Dev
Sure...I can work on this patch. I may just ask for a bit of guidance/
opinions on the best approach. Thank you all for your responses!

Sincerely,
Michelle

Michelle

unread,
Mar 3, 2011, 11:38:08 AM3/3/11
to Omeka Dev
Hi All,

I believe I am ready to submit the patch...I wanted to ask one quick
question first:

Initially I added the call to the filter into the constructor of
Admin.php (the Omeka_Controller_Plugin_Admin class).

However I noticed in a more recent version of the class the
constructor is gone. So instead
I'm planning to add the call to the filter into the preDispatch
function of the class. Any objections to this?

Here is the code I am planning to add:

//use a filter to add any needed additions to the whitelist
$this->_adminWhitelist = apply_filters('admin_whitelist', $this-
>_adminWhitelist);

Thanks for any thoughts/suggestions.

Sincerely,
Michelle

On Feb 4, 3:22 pm, Jeremy Boggs <jer...@clioweb.org> wrote:

John Flatness

unread,
Mar 3, 2011, 1:18:37 PM3/3/11
to omek...@googlegroups.com
Hi Michelle,

Yeah, that constructor went away in a fairly recent change, the code that used to be there moved to the admin bootstrap script.

Anyway, preDispatch seems like the natural place for this filter to go. The filter will get run right before the code that actually applies the whitelist.

-John

Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

John Flatness

unread,
Aug 24, 2012, 6:07:59 PM8/24/12
to omek...@googlegroups.com
A few notes on omeka-dev etiquette:

Though the Google Groups web interface can make it look like a web forum, many or most of the people on the list are subscribed and receive every post by email. So, please try not to double-post, cross-post, or post similar messages in different threads, since it means many people are getting your messages twice.

If you'd like to communicate with someone in particular, or you don't think they're "listening," it's probably best to email them directly, instead of posting to the list. Even if you respond to "their" thread, individual subscribers don't really get a lot of notification other than the subject line of the message.

Finally, the list isn't a great place to post code, other than smallish snippets. Code posted only here is likely to get lost or forgotten, or garbled by the list software and people copying and pasting the code. If you're looking to share your code, I'd recommend something like GitHub, Bitbucket, or Google Code, all of which will let you post, share, and update code for free. If you want to share something more quickly with less setup, something like gist.github.com or pastebin.com is a good option.

-John

On Aug 24, 2012, at 5:53 PM, omeka_ldap wrote:

<?php

   //Define hooks
   add_plugin_hook('install', 'ldap_install');
   add_plugin_hook('initialize', 'ldap_initialize');
   add_plugin_hook('config', 'ldap_config');
   add_plugin_hook('config_form', 'ldap_config_form');

   ///Define filters
   add_filter('login_adapter', 'login');
   add_filter('admin_whitelist','addToWhitelist');


   //Pull values from form & create LDAP Auth Adapter Object:
   function login($authAdapter,$loginForm) {

        //retrieve username and password 
        $username = $loginForm->getValue('username');
        $pwd = $loginForm->getValue('password');
        
        //get plugin settings:
        $server1 = array();
        //hard coding in the settings they do not need to change. 
        $server1["host"] = get_option('ldap_server');

        $server1["baseDn"] =  get_option('ldap_basedn');

        $server1["port"] = get_option('ldap_port');

      $server1["accountCanonicalForm"] = get_option('ldap_accountCanonicalForm') + 0;

        $server1["accountFilterFormat"] = get_option('ldap_accountFilterFormat');

      $server1["accountDomainName"] = get_option('ldap_accountDomainName');

      $server1["accountDomainNameShort"] = get_option('ldap_accountDomainNameShort');

      $server1["bindRequiresDn"] = get_option('ldap_bindRequiresDn');

        $server1["useSsl"] = get_option('ldap_useSsl');
        $server1["username"] = get_option('ldap_username');
        $server1["password"] = get_option('ldap_password');;
        $options = array($server1);
        
        $authAdapter = new Omeka_Auth_Adapter_Ldap($options,$username,$pwd);
        $authAdapter->setIdentity($username)->setCredential($pwd);
         
        return $authAdapter;
        
   }



    function addToWhitelist($adminWhiteList){
   
  array_push($adminWhiteList,array('controller' => 'ldap', 'action' => 'forgot-password'));
  return $adminWhiteList;
  
    }


    function ldap_initialize(){
  $front = Zend_Controller_Front::getInstance();
       Zend_Controller_Front::getInstance()->registerPlugin(new LdapControllerPlugin);
    
    }

function ldap_config() {
                set_option('ldap_server', trim($_POST['ldap_server']));
                set_option('ldap_port', trim($_POST['ldap_port']));
                set_option('ldap_basedn', trim($_POST['ldap_basedn']));
                //new in v .2
                set_option('ldap_accountCanonicalForm', trim($_POST['ldap_accountCanonicalForm']));
                set_option('ldap_accountFilterFormat',trim($_POST['ldap_accountFilterFormat']));
                set_option('ldap_accountDomainName',trim($_POST['ldap_accountDomainName']));
                set_option('ldap_accountDomainNameShort',trim($_POST['ldap_accountDomainNameShort']));
                set_option('ldap_bindRequiresDn',trim($_POST['ldap_bindRequiresDn']));
                set_option('ldap_useSsl',trim($_POST['ldap_useSsl']));
                set_option('ldap_username',trim($_POST['ldap_username']));
                set_option('ldap_password',trim($_POST['ldap_password']));
    }
function ldap_config_form() {
echo '<div id = "ldap_server">';
echo '<label for = "top_domain">Host (LDAP Server):</label>';
echo text (array('name'=>'ldap_server'), get_option('ldap_server'), null);
echo '<br />';
echo '<div id = "ldap_port">';
echo '<label for = "ldap_port">Port: </label>';
echo text (array('name'=>'ldap_port'), get_option('ldap_port'), null);
echo '<br />';
echo '<div id = "ldap_basedn">';
echo '<label for = "ldap_basedn">Base DN: </label>';
echo text (array('name'=>'ldap_basedn'), get_option('ldap_basedn'), null);
echo '<br />';
//new in v .2
echo '<div id = "ldap_accountCanonicalForm">';
echo '<label for = "ldap_accountCanonicalForm">Account Canonical Form: </label>';
echo text (array('name'=>'ldap_accountCanonicalForm'), get_option('ldap_accountCanonicalForm'), null);
echo '<br />';
echo '<div id = "ldap_accountFilterFormat">';
echo '<label for = "ldap_accountFilterFormat">Account Filter Format: </label>';
echo text (array('name'=>'ldap_accountFilterFormat'), get_option('ldap_accountFilterFormat'), null);
echo '<br />';
echo '<div id = "ldap_accountDomainName">';
echo '<label for = "ldap_accountDomainName">Account Domain Name: </label>';
echo text (array('name'=>'ldap_accountDomainName'), get_option('ldap_accountDomainName'), null);
echo '<br />';
echo '<div id = "ldap_accountDomainNameShort">';
echo '<label for = "ldap_accountDomainNameShort">Account Domain Name Short: </label>';
echo text (array('name'=>'ldap_accountDomainNameShort'), get_option('ldap_accountDomainNameShort'), null);
echo '<br />';
echo '<div id = "ldap_bindRequiresDn">';
echo '<label for = "ldap_bindRequiresDn">Bind Requires DN (true or false): </label>';
echo text (array('name'=>'ldap_bindRequiresDn'), get_option('ldap_bindRequiresDn'), null);
echo '<br />';
echo '<div id = "ldap_useSsl">';
echo '<label for = "ldap_useSsl">Use SSL (true or false): </label>';
echo text (array('name'=>'ldap_useSsl'), get_option('ldap_useSsl'), null);
                echo '<br />';
echo '<div id = "ldap_username">';
echo '<label for = "ldap_username">Username(usually a service account) to lookup actual dn with should be in dn format </label>';
echo text (array('name'=>'ldap_username'), get_option('ldap_username'), null);
echo '<br />';
echo '<div id = "ldap_password">';
echo '<label for = "ldap_password">Password for username: </label>';
echo text (array('name'=>'ldap_password'), get_option('ldap_password'), null);
}

 class Omeka_Auth_Adapter_Ldap extends Zend_Auth_Adapter_Ldap {
private $omeka_userid;
public function __construct($options,$username,$password) {
parent::__construct($options,$username,$password);
//The Zend_Auth_Result (returned from Zend_Auth_Adapter_Ldap)-- 'identity' attribute
//does not hold the username needed for omeka user 'id' lookup so $omeka_userid will hold it
$this->omeka_userid = $username;
}
public function authenticate() {
$authResult = parent::authenticate();
                $log_path = LOGS_DIR . '/' . 'ldap.log';
        if ($log_path) {
            $messages = $authResult->getMessages();

            $logger = new Zend_Log();
            $logger->addWriter(new Zend_Log_Writer_Stream($log_path));
            $filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
            $logger->addFilter($filter);

            foreach ($messages as $i => $message) {
                if ($i-- > 1) { // $messages[2] and up are log messages
                    $message = str_replace("\n", "\n  ", $message);
                    $logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
                }
            }
        }

if (!$authResult->isValid()) {
            return $authResult;
        }
        // Omeka needs the user ID (not username)
        $omeka_user = get_db()->getTable('User')->findBySql("username = ?", array($this->omeka_userid), true);
        if ($omeka_user) {
        $id = $omeka_user->id;
        $correctResult = new Zend_Auth_Result($authResult->getCode(), $id , $authResult->getMessages());
        return $correctResult;             
        }
        //if we can't find the user name in Omeka - return an error:
        //(The Omeka Admin should set up the LDAP username to match the Omeka Username)
        //Another alternative here 'could be' -- if needed -- creating a new Omeka User 
        else {
        $messages = array();
        $messages[] = 'Login information incorrect. Please try again.';
        $authResult = new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $this->omeka_userid , $messages);
        return $authResult;
        }
}
 }

 class LdapControllerPlugin extends Zend_Controller_Plugin_Abstract {
    public function routeStartup(Zend_Controller_Request_Abstract $request) {
    $router = Omeka_Context::getInstance()->getFrontController()->getRouter();
        
         $route = new Zend_Controller_Router_Route(
    'users/forgot-password',
    array(
     'module'     => 'ldap', 
         'controller' => 'ldap',
         'action'     => 'forgot-password'
    ));
 
$router->addRoute('forgot', $route);
        $route = new Zend_Controller_Router_Route(
    'users/add',
    array(
    'module'     => 'ldap', 
        'controller' => 'ldap',
        'action'     => 'add'
    ));
 
$router->addRoute('addLdapUser', $route);
$route = new Zend_Controller_Router_Route(
    'users/edit/:id',
    array(
    'module'       => 'ldap', 
        'controller' => 'ldap',
        'action'     => 'edit'
    ));
 
$router->addRoute('editLdapUser', $route);
    }
   
 }


On Wednesday, August 22, 2012 12:32:01 PM UTC-4, omeka_ldap wrote:
I am assume you are from lehigh and this is your plugin I am modifying? 

On Wednesday, August 22, 2012 11:28:47 AM UTC-4, omeka_ldap wrote:
I got ssl working, but I am unable to add logging. 
<?php

   //Define hooks
   add_plugin_hook('install', 'ldap_install');
   add_plugin_hook('initialize', 'ldap_initialize');
   add_plugin_hook('config', 'ldap_config');
   add_plugin_hook('config_form', 'ldap_config_form');

   ///Define filters
   add_filter('login_adapter', 'login');
   add_filter('admin_whitelist','addToWhitelist');


   //Pull values from form & create LDAP Auth Adapter Object:
   function login($authAdapter,$loginForm) {

        //retrieve username and password 
        $username = $loginForm->getValue('username');
        $pwd = $loginForm->getValue('password');
        
        //get plugin settings:
        $server1 = array();
        $server1["host"] = get_option('ldap_server');
        $server1["baseDn"] =  get_option('ldap_basedn');
        $server1["port"] = get_option('ldap_port');
      $server1["accountCanonicalForm"] = get_option('ldap_accountCanonicalForm') + 0;
        $server1["accountFilterFormat"] = get_option('ldap_accountFilterFormat');
      $server1["accountDomainName"] = get_option('ldap_accountDomainName');
      $server1["accountDomainNameShort"] = get_option('ldap_accountDomainNameShort');
      $server1["bindRequiresDn"] = get_option('ldap_bindRequiresDn');
        $server1["useSsl"] = "true";
        $options = array($server1);
        
        $authAdapter = new Omeka_Auth_Adapter_Ldap($options,$username,$pwd);
        $authAdapter->setIdentity($username)->setCredential($pwd);
         
        return $authAdapter;
        
   }



    function addToWhitelist($adminWhiteList){
   
  array_push($adminWhiteList,array('controller' => 'ldap', 'action' => 'forgot-password'));
  return $adminWhiteList;
  
    }


    function ldap_initialize(){
  $front = Zend_Controller_Front::getInstance();
       Zend_Controller_Front::getInstance()->registerPlugin(new LdapControllerPlugin);
    
    }

function ldap_config() {
set_option('ldap_server', trim($_POST['ldap_server']));
set_option('ldap_port', trim($_POST['ldap_port']));
set_option('ldap_basedn', trim($_POST['ldap_basedn']));
//new in v .2
set_option('ldap_accountCanonicalForm', trim($_POST['ldap_accountCanonicalForm']));
set_option('ldap_accountFilterFormat',trim($_POST['ldap_accountFilterFormat']));
set_option('ldap_accountDomainName',trim($_POST['ldap_accountDomainName']));
set_option('ldap_accountDomainNameShort',trim($_POST['ldap_accountDomainNameShort']));
set_option('ldap_bindRequiresDn',trim($_POST['ldap_bindRequiresDn']));
    }
function ldap_config_form() {
echo '<div id = "ldap_server">';
echo '<label for = "top_domain">Host (LDAP Server):</label>';
echo text (array('name'=>'ldap_server'), get_option('ldap_server'), null);
echo '<br />';
echo '<div id = "ldap_port">';
echo '<label for = "ldap_port">Port: </label>';
echo text (array('name'=>'ldap_port'), get_option('ldap_port'), null);
echo '<br />';
echo '<div id = "ldap_basedn">';
echo '<label for = "ldap_basedn">Base DN: </label>';
echo text (array('name'=>'ldap_basedn'), get_option('ldap_basedn'), null);
echo '<br />';
//new in v .2
echo '<div id = "ldap_accountCanonicalForm">';
echo '<label for = "ldap_accountCanonicalForm">Account Canonical Form: </label>';
echo text (array('name'=>'ldap_accountCanonicalForm'), get_option('ldap_accountCanonicalForm'), null);
echo '<br />';
echo '<div id = "ldap_accountFilterFormat">';
echo '<label for = "ldap_accountFilterFormat">Account Filter Format: </label>';
echo text (array('name'=>'ldap_accountFilterFormat'), get_option('ldap_accountFilterFormat'), null);
echo '<br />';
echo '<div id = "ldap_accountDomainName">';
echo '<label for = "ldap_accountDomainName">Account Domain Name: </label>';
echo text (array('name'=>'ldap_accountDomainName'), get_option('ldap_accountDomainName'), null);
echo '<br />';
echo '<div id = "ldap_accountDomainNameShort">';
echo '<label for = "ldap_accountDomainNameShort">Account Domain Name Short: </label>';
echo text (array('name'=>'ldap_accountDomainNameShort'), get_option('ldap_accountDomainNameShort'), null);
echo '<br />';
echo '<div id = "ldap_bindRequiresDn">';
echo '<label for = "ldap_bindRequiresDn">Bind Requires DN (true or false): </label>';
echo text (array('name'=>'ldap_bindRequiresDn'), get_option('ldap_bindRequiresDn'), null);
}

 class Omeka_Auth_Adapter_Ldap extends Zend_Auth_Adapter_Ldap {
private $omeka_userid;
public function __construct($options,$username,$password) {
parent::__construct($options,$username,$password);
//The Zend_Auth_Result (returned from Zend_Auth_Adapter_Ldap)-- 'identity' attribute
//does not hold the username needed for omeka user 'id' lookup so $omeka_userid will hold it
$this->omeka_userid = $username;
}
public function authenticate() {
$authResult = parent::authenticate();
                $log_path = "/home/httpd/myuser/application/logs/ldap.log";
        if ($log_path) {
            $messages = $authResult->getMessages();

            $logger = new Zend_Log();
            $logger->addWriter(new Zend_Log_Writer_Stream($log_path));
            $filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
            $logger->addFilter($filter);

            foreach ($messages as $i => $message) {
                if ($i-- > 1) { // $messages[2] and up are log messages
                    $message = str_replace("\n", "\n  ", $message);
                    $logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
                }
            }
        }

if (!$authResult->isValid()) {
            return $authResult;
        }
        // Omeka needs the user ID (not username)
        $omeka_user = get_db()->getTable('User')->findBySql("username = ?", array($this->omeka_userid), true);
        if ($omeka_user) {
        $id = $omeka_user->id;
        $correctResult = new Zend_Auth_Result($authResult->getCode(), $id , $authResult->getMessages());
        return $correctResult;
        }
        //if we can't find the user name in Omeka - return an error:
        //(The Omeka Admin should set up the LDAP username to match the Omeka Username)
        //Another alternative here 'could be' -- if needed -- creating a new Omeka User 
        else {
        $messages = array();
        $messages[] = 'Login information incorrect. Please try again.';
        $authResult = new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $this->omeka_userid , $messages);
        return $authResult;
        }
}
 }

 class LdapControllerPlugin extends Zend_Controller_Plugin_Abstract {
    public function routeStartup(Zend_Controller_Request_Abstract $request) {
    $router = Omeka_Context::getInstance()->getFrontController()->getRouter();
        
         $route = new Zend_Controller_Router_Route(
    'users/forgot-password',
    array(
     'module'     => 'ldap', 
         'controller' => 'ldap',
         'action'     => 'forgot-password'
    ));
 
$router->addRoute('forgot', $route);
        $route = new Zend_Controller_Router_Route(
    'users/add',
    array(
    'module'     => 'ldap', 
        'controller' => 'ldap',
        'action'     => 'add'
    ));
 
$router->addRoute('addLdapUser', $route);
$route = new Zend_Controller_Router_Route(
    'users/edit/:id',
    array(
    'module'       => 'ldap', 
        'controller' => 'ldap',
        'action'     => 'edit'
    ));
 
$router->addRoute('editLdapUser', $route);
--
You received this message because you are subscribed to the Google Groups "Omeka Dev" group.
To view this discussion on the web visit https://groups.google.com/d/msg/omeka-dev/-/upDLqMur89IJ.
Reply all
Reply to author
Forward
0 new messages