openITCOCKPIT icon indicating copy to clipboard operation
openITCOCKPIT copied to clipboard

No auto provisioning and role mapping available

Open SimonBin opened this issue 6 years ago • 7 comments

ideally there should be some option to automatically create users that log in to openITCOCKPIT

as a proof of concept, I came up with the following hardcoded patch which works against simplesamlphp (it uses the sp userinfo for provisioning, but extending this to ldap would be good) and creates a lot of admin users in the /root container. better would be a mapping configuration to do this based on ldap group membership.

since I don't understand php, my code is running into a small issue where it shows This action is not allowed. on log in above You have been automatically logged in.. Not sure exactly which action is not allowed :-(

diff --git a/app/Controller/LoginController.php b/app/Controller/LoginController.php
index 1a66c27..52f19b8 100644
--- a/app/Controller/LoginController.php
+++ b/app/Controller/LoginController.php
@@ -27,7 +27,7 @@ use itnovum\openITCOCKPIT\Core\Views\Logo;
 {
 
     public $uses = ['User', 'SystemContent', 'Systemsetting', 'Container', 'Oauth2client'];
-    public $components = ['Ldap'];
+    public $components = ['Ldap', 'Upload'];
 
     public $layout = 'login';
 
@@ -46,6 +45,63 @@ class LoginController extends AppController
         $this->redirect('/login/login');
     }
 
+    public function provisionUser($result)
+    {
+        $systemsettings = $this->Systemsetting->findAsArraySection('FRONTEND');
+
+        $this->User->clear();
+        $user = $this->User->find('first', ['conditions' => ['email' => $result['email'], 'status' => 1]]);
+        if ($systemsettings['FRONTEND']['FRONTEND.SSO.NO_EMAIL_MESSAGE'] != 'CREATE') {
+            return $user;
+        }
+        $user = $this->User->find('first', ['conditions' => ['samaccountname' => $result['attributes']['uid'][0], 'status' => 1]]);
+        if(empty($user)){
+            $this->User->create();
+            $user = array('User' => array(), 'ContainerUserMembership' => array());
+        }else{
+            $this->User->id = $user['User']['id'];
+        }
+        $user['User']['Container'] = array(0 => '1');
+        $user['User']['usergroup_id'] = 1;
+        $user['User']['status'] = Status::ACTIVE;
+        $user['User']['samaccountname'] = $result['attributes']['uid'][0];
+        $user['User']['email'] = $result['email'];
+        $user['User']['firstname'] = $result['attributes']['givenName'][0];
+        $user['User']['lastname'] = $result['attributes']['sn'][0];
+        $user['ContainerUserMembership'][0] = array(
+            'container_id' => 1,
+            'permission_level' => 2,
+        );
+        $saveOpts = array('validate' => false);
+        if($this->User->saveAssociated($user, $saveOpts)){
+            if(!empty($result['attributes']['jpegPhoto'])){
+                if (!file_exists(WWW_ROOT.'userimages')) {
+                    mkdir(WWW_ROOT.'userimages');
+                }
+                $this->Upload->setPath(WWW_ROOT.'userimages'.DS);
+                $tmpimg = UUID::v4();
+                $handle = fopen($this->Upload->path . $tmpimg, "wb");
+                fwrite($handle, base64_decode($result['attributes']['jpegPhoto'][0]));
+                fclose($handle);
+                $filename = UUID::v4().'.png';
+                if ($this->Upload->createUserimage($tmpimg, $filename)) {
+                    if ($this->User->saveField('image', $filename)) {
+                        //Delete old image
+                        if (!empty($user) && file_exists(WWW_ROOT.'userimages'.DS.$user['User']['image']) && !is_dir(WWW_ROOT.'userimages'.DS.$user['User']['image'])) {
+                            unlink(WWW_ROOT.'userimages'.DS.$user['User']['image']);
+                        }
+                    }
+                }else{
+                    unlink($this->Upload->path . $tmpimg);
+                }
+            }
+        }else{
+        }
+        $this->User->clear();
+        $user = $this->User->find('first', ['conditions' => ['samaccountname' => $result['attributes']['uid'][0], 'status' => 1]]);
+        return $user;
+    }
+
     public function login($redirectBack = 0)
     {
         $systemsettings = $this->Systemsetting->findAsArraySection('FRONTEND');
@@ -57,7 +113,7 @@ class LoginController extends AppController
                 $this->redirect($result['redirect']);
             }
             if(($result['success'])) {
-                $user = $this->User->find('first', ['conditions' => ['email' => $result['email'], 'status' => 1]]);
+                $user = $this->provisionUser($result);
                 if(empty($user)){
                     echo $systemsettings['FRONTEND']['FRONTEND.SSO.NO_EMAIL_MESSAGE'].$errorPostMess;exit;
                 }
diff --git a/app/Model/Oauth2client.php b/app/Model/Oauth2client.php
index 2dcde9e..7d96dfd 100644
--- a/app/Model/Oauth2client.php
+++ b/app/Model/Oauth2client.php
@@ -75,7 +75,7 @@ class Oauth2client
                 return ['success' => false, 'message' => 'Can not get user data: '.(ENVIRONMENT === 'production' ? '' : $userDataArr[1])];
             }
             $userArray = $userDataArr[1]->toArray();
-            return ['success' => true, 'email' => $userArray['mail']];
+            return ['success' => true, 'email' => $userArray['mail'][0], 'attributes' => $userArray['attributes']];
         }
     }
 
-- 
2.7.4

SimonBin avatar Apr 04 '18 16:04 SimonBin

Hello @SimonBin,

action "provisionUser" is not allowed. For this case you can modify acl_dependecies.php : https://github.com/it-novum/openITCOCKPIT/blob/development/app/Config/acl_dependencies.php#L351

diff --git a/app/Config/acl_dependencies.php b/app/Config/acl_dependencies.php
index 8f8c895..5d969ef 100644
--- a/app/Config/acl_dependencies.php
+++ b/app/Config/acl_dependencies.php
@@ -348,7 +348,7 @@ $config = [
                 'Hosttemplates'         => ['index', 'usedBy'],
                 'Locations'             => ['index'],
                 'Logentries'            => ['index'],
-                'Login'                 => ['index', 'login', 'onetimetoken', 'logout', 'auth_required', 'lock'],
+                'Login'                 => ['index', 'login', 'onetimetoken', 'logout', 'auth_required', 'lock', 'provisionUser'],
                 'Macros'                => ['index'],
                 'Nagiostats'            => ['index'],
                 'Notifications'         => ['index', 'hostNotification', 'serviceNotification'],

openitcockpit-update (command must be executed from the console)

This allow to execute "provisionUser" action in LoginController

Best regards

ibering avatar Apr 05 '18 09:04 ibering

Ho @SimonBin, I created an API example script, which will create all users from your LDAP into openITCOCKPIT. You can find this here: https://github.com/it-novum/openITCOCKPIT-LDAP-API-Importer

All users will be created to the container /root. You can modify this if required.

Unfortunately at the moment the LDAP scan in openITCOCKPIT is not available via the json API. To resolve this issue, you need to apply the following patch: (will be also included in Version 3.4)

diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php
index e667aab..0635950 100644
--- a/app/Controller/UsersController.php
+++ b/app/Controller/UsersController.php
@@ -395,6 +395,7 @@ class UsersController extends AppController
         $systemsettings = $this->Systemsetting->findAsArraySection('FRONTEND');

         $this->set(compact(['usersForSelect', 'systemsettings']));
+        $this->set('_serialize', ['usersForSelect']);
     }

     public function resetPassword($id = null)

Hope this helps :)


For security reasons, we decided not to create users automatically just because they exists in LDAP. This prevents to leak sensitive information.

Regards, Daniel

nook24 avatar Apr 05 '18 09:04 nook24

hi @ibering , thanks for your comment. Your suggestion did not change anything. Note that the login works, it's just this strange flash message. But this is just a minor issue with my proof of concept, writing a complete provisioning solution is likely a bit more work...

here is the stack trace of the flash:

#0 /usr/share/openitcockpit/lib/Cake/Controller/Component/AuthComponent.php(306): AuthComponent->_unauthenticated(Object(DashboardsController))
#1 /usr/share/openitcockpit/lib/Cake/Utility/ObjectCollection.php(128): AuthComponent->startup(Object(DashboardsController))
#2 /usr/share/openitcockpit/lib/Cake/Event/CakeEventManager.php(243): ObjectCollection->trigger('startup')
#3 /usr/share/openitcockpit/lib/Cake/Controller/Controller.php(678): CakeEventManager->dispatch(Object(CakeEvent))
#4 /usr/share/openitcockpit/lib/Cake/Routing/Dispatcher.php(189): Controller->startupProcess()
#5 /usr/share/openitcockpit/lib/Cake/Routing/Dispatcher.php(167): Dispatcher->_invoke(Object(DashboardsController), Object(CakeRequest))
#6 /usr/share/openitcockpit/app/webroot/index.php(110): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse))
#7 {main}

to me this looks like the dashboard thinks I'm not logged in or something

hi @nook24 , thanks also for your script. We are looking for some ideas how to automatically keep openITC up to date with ldap, so a one time import could be annoying.

In fact we have this simple requirement: when users log in, they should get an account. and when they are deleted they should not be able to log in. Also, notification contacts etc should be able to search/select from ldap.

I haven't looked at this in detail yet though. Will it just ignore already existing users when ran over and over? I guess I still need to remove users that were removed from ldap manually as well, right?

SimonBin avatar Apr 05 '18 09:04 SimonBin

If an user already exists, the script will just ignore this one and continue with the next user, so you can execute it as cronjob to keep openITCOCKPIT in sync.

Deleted users will be still available in openITCOCKPIT, but are not able to login anymore, because the LDAP server will deny the authentication.

To create an contact via LDAP, the API endpoint is:

/contacts/add/ldap:1/email:<[email protected]>/samaccountname:<foobar>/fix:1.json

You can take a look at our "Configuration Importer" to see an example API request to create an contact: https://github.com/it-novum/openITCOCKPIT-configuration-import/blob/master/src/itnovum/openITCOCKPIT/Migration/Objects/Contact.php#L83

nook24 avatar Apr 05 '18 10:04 nook24

ok I will try to work with cron job + importer. ... for now I'm first trying to make LDAP work at all...

is it possible to make the email address updatable?

SimonBin avatar Apr 05 '18 11:04 SimonBin

Since openITCOCKPIT 4.4.0 it is possible, to automatically set user permissions based on LDAP groups.

You still have to create the user in openITCOCKPIT first, but this can be automated using an API script. Depending on the users LDAP groups, openITCOCKPIT will grant permissions to to user. Please see https://docs.openitcockpit.io/en/configuration/ldap-integration/#automatic-permissions-via-ldap-groups for more information about this.

nook24 avatar Apr 26 '22 12:04 nook24

thanks for the answer!

SimonBin avatar May 05 '22 10:05 SimonBin

I will close this as i think this feature got implemented with openITCOCKPIT 4.4.0.

Feel free to open a new issue in case you have any feature requests or issues.

nook24 avatar Feb 16 '23 14:02 nook24