Closed tbeg closed 7 years ago
Hi
@laurentj has coded a new driver called ldapdao to handle users from a LDAP Server, but still uses a PostGreSQL or sqlite backend to store Lizmap-specific rights. This subject is more related to https://github.com/jelix/jelix . This driver would be available in a next lizmap version
I opened issue jelix/jelix#193 ;-)
The plugin is here (embedded into a module) : https://github.com/jelix/ldapdao-module
If you have some difficulties to configure it, ask your questions and so I could improve the documentation.
Hello I read the lizmap documentation
If I'm not wrong Lizmap needs a new entire postgresql database to store credentials and other things it needs Is it so? Is it possible to use a given schema in a existing database to store credentials instead of a new database?
Then, is it possible to map the user that is editing a layer instead of the user saved in the connection string on the Qgis project file? As asked here? https://github.com/3liz/lizmap-web-client/issues/457
Thanks Pietro
My answers:
No, lizmap does not need a new different database. It uses the database defined in the lizmap/var/config/profiles.ini.php when Lizmap is installed. You can even create the tables manually (or import them from a previous Lizmap installation) in a database, and use them in Lizmap.
NB: I wont answer here to the last question linked to #457 in this issue, to avoid cross-posting.
Thanks @mdouchin in the guide I don't see a schema variable
If I set schema="myschema" does lizmap use that for its tables? Otherwise, which tables should I create to serve Lizmap with the correct space to store its informations?
;Example of different driver (e.g PostgreSQL) [jdb:jauth] driver="pgsql" database="name_of_database" host="localhost" user="Admin_user_postgreSQL" password="put_here_the_password"
[jdb:lizlog] driver="pgsql" database="name_of_database" host="localhost" user="Admin_user_postgreSQL" password="put_here_the_password"
You could use a search_path variable with a list of schemas separated by comma.
search_path="myschema,public"
You can see which tables to create here: https://github.com/3liz/lizmap-web-client/blob/master/lib/jelix-modules/jauthdb/install/install_jauth.schema.pgsql.sql and here https://github.com/3liz/lizmap-web-client/blob/master/lib/jelix-modules/jacl2db/install/install_jacl2.schema.pgsql.sql
(replace %%PREFIX%% with your schema)
hi @laurentj @mdouchin
i intend to try the ldap authentication
INSTALLATION
my questions:
folder where i put the plugin: lib, jelix, jelix/plugins or jelix-modules ?
folder name that contains the plugin: ldapdao-module or ldapdao ?
declare the module into the configuration of your application --> localconfig.ini.php [modules] ldapdao.access=1
declare the path to ldapdao-module in the modulesPath --> mainconfig.ini.php modulesPath="lib:jelix-admin-modules/,lib:jelix-modules/,app:modules/,app:lizmap-modules" what should i add here ?
modules are required: jacl2, jauth, jauthdb --> nothing to do ?
php yourapp/cmd.php install --> php lizmap/install/installer.php
thank you in advance
folder where i put the plugin: lib, jelix, jelix/plugins or jelix-modules
You must put nothing in lib/ and its child directories, else you'll have difficulties to upgrade Lizmap. Everything you want to add should be stored inside lizmap/.
Copy the ldapdao directories (from https://github.com/jelix/ldapdao-module ) into lizmap/lizmap-modules/.
declare the module into the configuration of your application --> localconfig.ini.php
Yes.
declare the path to ldapdao-module in the modulesPath --> mainconfig.ini.php
do nothing if you install it into lizmap/lizmap-modules/.
modules are required: jacl2, jauth, jauthdb --> nothing to do ?
No, it is already activated for Lizmap (see the mainconfig.ini.php)
php yourapp/cmd.php install --> php lizmap/install/installer.php
Yes. or php lizmap/cmd.php install. This is the same thing.
sorry for the noise...
now i'm trying with a fresh install (master versions), step by step. i'm using the authldap.coord.ini.php file without any changes and i don't get messages related to ldap server (only "Failed to login")
what is missing? something in profiles.ini.php file?
[jdb]
; name of the default profile to use for any connection default=jauth jacl2_profile=jauth
[jdb:jauth] driver=sqlite3 database="var:db/jauth.db"
thanks again
In fact the var/config/admin/config.ini.php and var/config/index/config.ini.php redefine the path of the auth config. So you should change also them :
[coordplugins]
auth="authldap.coord.ini.php"
Other changes to do into authldap.coord.ini.php
after_login = "view~default:index"
persistant_crypt_key="change it to any other sentence, it is used to encrypt cookies"
Be careful, you have two "searchGroupFilter=", and the last is empty : it will override the value that is above it.
For other ldap values (uidProperty, bindUserDN, searchBaseDN, searchUserFilter, searchUserListFilter, searchUserListReturnsUser, searchUserListUserUidAttribute, searchAttributes, searchGroupFilter, searchGroupProperty), be sure it corresponds to your ldap structure. Check them with the ldap administrator. Anyway I can't help you on these values as I'm not very familiar with ldap.
Be sure also to remove all files from temp/lizmap/. Sometimes temporary files are not all updated when the configuration changes.
hi @laurentj
thanks for your helps
after following all your instructions, i'm at this point now:
error [612] ldap extension unloaded /var/www/html/lizmap-web-client-master/lizmap/lizmap-modules/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php 23
thanks again
hi @laurentj
i'm familiar with ldap server, i have some applications to do ldap authentication, like zimbra mail server, openfire messenger server, printing systems, etc.
i just need your help to get to the point of communication between the LWC and the ldap server
fter installing the php ldap module, i think i'm at that point now
warning ldap_bind(): Unable to bind to server: Invalid credentials /var/www/html/lizmap-web-client-master/lizmap/lizmap-modules/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php 169
hi @laurentj
i can already get ldap authentication with: bindUserDN="uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt" --> DN: uid=foo,ou=Users,dc=cmarl,dc=pt
but my openldap structure is different than expected: bindUserDN="cn=??????,ou=users,dc=cmarl,dc=pt" --> DN: cn=foo xpto,ou=Users,dc=cmarl,dc=pt
could you please contemplate this kind of structure in your module code (authldap.coord.ini.php)?
could you please contemplate this kind of structure in your module code
Why ? just modify the parameter bindUserDN to match your ldap structure...
bindUserDN="cn=%%USERNAME%% xpto,ou=users,dc=cmarl,dc=pt"
No ?
Or perhaps i didn't understand what do you expect..
sorry, maybe i did not explain myself well
in openldap users structure there are 3 default users (admin, Administrator and nobody) for which the distinguished name (DN) is composed as follows:
DN: uid=admin,ou=Users,dc=cmarl,dc=pt
for these users i can get ldap authentication, using:
uidProperty=uid
bindUserDN="uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt"
for all other users the DN is composed as follows:
DN: cn=Jose Macau,ou=Users,dc=cmarl,dc=pt
however, the user to login has to provide his uid, not his cn
for these users i can't get ldap authentication, using as you suggest:
uidProperty=uid
bindUserDN="**cn=%%USERNAME%%**,ou=users,dc=cmarl,dc=pt"
warning ldap_bind(): Unable to bind to server: Invalid credentials /var/www/html/lizmap-web-client-master/lizmap/lizmap-modules/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php 169
@josemvm Ok, If I understood well, the bindUserDN
is different according to the type of user. So, a solution could be the possibility to indicate several bindUserDN values, and then the connector will try each one until a success. Right ?
For example, we could have this possibility in the configuration :
bindUserDN[]="uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt"
bindUserDN[]="cn=%%USERNAME%%,ou=users,dc=cmarl,dc=pt"
(note the brackets []
, that indicates an item of a list)
Then, when the connector will try to connect, it will try first with uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt
, and if it fails, it will try with cn=%%USERNAME%%,ou=users,dc=cmarl,dc=pt
and so on...
If I implement such behavior, will it fix your issue?
yes, theoretically correct
if you can provide me same code, i'll test and send you feedback before you implement it
@josemvm I pushed the new implementation
Get the source code of ldapdao.auth.php here, and set the configuration like this:
bindUserDN[]="cn=%%USERNAME%%,ou=users,dc=cmarl,dc=pt"
bindUserDN[]="uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt"
The order is important. Probably the first one should correspond to the most of users, the last one to specific users, in order to limit the number of failed tries during the life of the app.
tell me if it works :-)
hi @laurentj
i'll give you soon a cleaner feedback
hi @laurentj
first time: login with user uid (Administrator) and create the user in jauth.db
lizmap-web-client-master/lizmap/var/log/error.log warning [2] usort() expects parameter 2 to be a valid callback, function 'mainViewItemSort' not found or invalid function name /var/www/html/lizmap-web-client-master/lizmap/modules/view/zones/main_view.zone.php 138 (message number 1)
next time: login ok the same warning (log 1)
conclusion: the module works without any problems as usual
first time: login with user cn (Jose Macau) and create the user in jauth.db the same warning (log 1)
next time: never connect again with user cn warning [2] SQLite3::exec(): UNIQUE constraint failed: jlx_user.usr_login /var/www/html/lizmap-web-client-master/lib/jelix/plugins/db/sqlite3/sqlite3.dbconnection.php 120
error [403] invalid query (UNIQUE constraint failed: jlx_user.usr_login (INSERT INTO jlx_user (usr_login,usr_email,usr_password,firstname,lastname,organization,phonenumber,street,postcode,city,country,comment) VALUES ('ze_macau', 'mymail@domain.pt', 'no password', 'José', 'Macau', NULL, NULL, NULL, NULL, NULL, NULL, NULL))) /var/www/html/lizmap-web-client-master/lib/jelix/plugins/db/sqlite3/sqlite3.dbconnection.php 123
reflection 1: it seems to me that it try to create again the same user with the same primary key and fail...
if i try to login with uid (ze_macau) as desired and expected, "failed to login" without errors log
reflection 2: it seems to me that it need a function that could extract the user cn from corresponding user uid using _bindLdapAdminUser function, and assign this value to the bindUserDN and allow user to login with it.
but i don't know, honestly i have no programming skills.
thanks again for your work
Sorry for the delay.
I will take a look on this issue next days.
hi @laurentj
everything is quiet, it's not an urgent matter
thanks
Hi @josemvm
I try to understand what is the problem.
When it is uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt ̀
, you must enter "ze_macau" in the login form. But when it is cn=%%USERNAME%%,ou=users,dc=cmarl,dc=pt
, you must enter "Jose Macau". Right?
And in the configuration searchAttributes
, you have a thing like "uid:login", right?
If yes at both, then I think I found the bug. When you enter "Jose Macau", the plugin searches the user into the database, by using the given login "Jose Macau". It doesn't find it, so it creates a new record. But before that, it retrieves the user's attributes, and because of the value of searchAttributes
, the login is changed from "Jose Macau" to "ze_macau". As the login is the primary key in the table, the first time it works, the record is created, but the second time it fails. So in fact, the plugin should retrieve attributes first before checking the existance of the user in the database, to search with the uid, not the given cn.
Hi @laurentj,
And in the configuration searchAttributes, you have a thing like "uid:login", right?
Yes.
For uid='ze_macau' and cn='Jose Macau' my bindUserDN="cn=Jose Macau,ou=users,dc=cmarl,dc=pt", it's the way that my ldap server will do the authentication. But i want to give it the uid(ze_macau) and not the cn(Jose Macau), so the plugin should retrieve attributes first, as you said and then by the uid find the cn and try the authentication.
Thanks in advance.
ok, thank you, that's clear for me now :-)
Hi @laurentj and @josemvm I have had the same issue with a client using ActiveDirectory.
I propose this diff wich is a workaround. @josemvm Can you try it ? -> updated diff on last post
With this patch, I have used the configurations:
searchAttributes="cn,distinguishedName,name"
to be able to get the distinguishedName from the LDAP server
NB : context explained here http://stackoverflow.com/questions/8324785/authenticating-user-with-ldap-from-php-with-only-samaccountname-and-password
There is no way to connect via sAMAccountName and password, but we need to use distinguishedName
Updated diff after some fixes
diff --git a/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php b/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php
index 56552c6..3028015 100644
--- a/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php
+++ b/ldapdao/plugins/auth/ldapdao/ldapdao.auth.php
@@ -180,6 +180,24 @@ class ldapdaoAuthDriver extends jAuthDriverBase implements jIAuthDriver {
}
ldap_close($connect);
+ // First pass with direct login has not worked
+ // Connect as admin, to get more information on the user
+ // This is necessary in ActiveDirectory to get the user by distinguishedName
+ if(!$bind){
+ $aconnect = $this->_bindLdapAdminUser();
+
+ // Create user instance, but do not insert it into database
+ $user = $this->createUserObject($login, '');
+
+ //get ldap user infos: name, email etc...
+ if($checkUser = $this->searchLdapUserAttributes($aconnect, $login, $user)){
+ $connect = $this->_getLinkId();
+ $bind = @ldap_bind($connect, $user->distinguishedName, $password);
+ ldap_close($connect);
+ }
+ ldap_close($aconnect);
+ }
+
if (!$bind) {
jLog::log('ldapdao: cannot bind to any configured path with the login '.$login, 'auth');
return false;
hi @mdouchin
i tried to use your patch without your configurations
searchAttributes="cn,distinguishedName,name"
but in my case it doesn't work, the problem remains the same
my ldap DN = cn,ou,dc,dc
example:
For uid='ze_macau' and cn='Jose Macau' my bindUserDN="cn=Jose Macau,ou=users,dc=cmarl,dc=pt", it's the way that my ldap server will do the authentication. But i want to give it the uid(ze_macau) and not the cn(Jose Macau), so the plugin should retrieve attributes first, as you said and then by the uid find the cn and try the authentication.
@laurentj and @mdouchin i send you a java code file which is used to my ldap authentication, so please take a look at it
@mdouchin please check your mail box and share the file with @laurentj
@josemvm please replace in my 'patch' the distinguishedName by bindUserDN
and use the following parameter in the config ( see the use of all fields required to match ldap parameters and lizmap field names, and at the end the bindUserDN )
searchAttributes="uid:login,givenName:firstname,sn:lastname,mail:email,bindUserDN,name"
It seems our server need the full DN to authenticate a user:
And they cannot use something simple like uid=%%USERNAME%%,ou=users,dc=cmarl,dc=pt
so we need to get the data from the LDAP server for the user, including bindUserDN (or distinguishedName in my case )
Please test it and report This should work but obviously we should add a property in LDAP configuration "Use this property as DN to authenticate for the user if the server forces the use of full DN for authentication"
@mdouchin the problem remains
first time: only login with user cn (Jose Macau) and create the user in jauth.db, but not with uid='ze_macau' (as expected)
next time: never connect again with user cn (Jose Macau) and also not with uid='ze_macau'
@josemvm you should not log in with the cn but with the uid. Please post a Gist (or a pastebin) where we can see the content of the authldap config file (REMOVE THE PASSWORD)
@laurentj PR with new option here https://github.com/jelix/ldapdao-module/pull/3
The solution that I will implement:
searchUserFilter
filter and the given login. There will be the possibility to setup different searchUserFilter
, so it could try different filter, as some DN schemes may be different between users, like @josemvm has.searchUserIdAttribute
configuration property.bindUserDN
, to bind with the ldap, to verify that the given password is correct.I'm not sure if trying several different bindUserDN
is needed (for example, should we need a bindUserDN filter for each searchUserFilter?)
What do you think about it ?
hi @laurentj and @mdouchin thanks for your efforts.
i think you are rigth @laurentj , but what do you want to say with the
searchUserIdAttribute
i can't find it in authldap.coord.ini.php!
if i add it searchUserIdAttribute="cn";
how can i then use it on binUserDn
?
eg:
searchUserIdAttribute="cn"; bindUserDN[]="cn=%%searchUserIdAttribute%%,ou=users,dc=cmarl,dc=pt"
something like that?...
i can't find it in authldap.coord.ini.php!
yes, because it does not exist yet ;-) But in fact, it is similar to the uidProperty
property...
However, I will improve the solution like this, to ease and support requirements from both, you @josemvm and @mdouchin.
searchUserFilter
filter and the given login. There will be the possibility to setup different searchUserFilter
, so it could try different filters, as some DN schemes may be different between users, like @josemvm has.bindUserDN
to bind with the ldap, to verify that the given password is correct. a bindUserDN value may follow this syntax :
bindUserDN[]="cn=?,ou=users,dc=cmarl,dc=pt"
will use the cn attribute from the result found by the filter @josemvm, the configuration might become:
searchUserFilter="(&(objectClass=*)(cn=%%LOGIN%%))"
bindUserDN[]="cn=?,ou=users,dc=cmarl,dc=pt"
bindUserDN[]="uid=?,ou=users,dc=cmarl,dc=pt"
So, the result has the cn that is equals to the given login. The plugin will then try the first DN with the cn attribute value of the result, and if it fails, it will try the second DN with the uid attribute value of the result.
@mdouchin , the configuration might become:
searchUserFilter="(sAMAccountName=%%LOGIN%%)"
bindUserDN="$dn"
In this case, to bind to the ldap server, it will take the dn attribute value from the result that has the given login as a value of the attribute sAMAccountName.
Is it better?
ok @laurentj
it seems perfect to me, go ahead!
thanks
I'm currently implementing the solution :-)
nice! have a good day at work :-)
I made the changes, but not tested yet. Can you verify that it works for you?
Note that i made a little modification into the specification: in bindUserDN, use %?%
instead of ?
.
hi @laurentj
excellent!!!
now, i can get authentication from my ldap with
searchUserFilter="(&(objectClass=*)(cn=%%LOGIN%%))"
for cn (just an experiment)
or with
searchUserFilter="(&(objectClass=*)(uid=%%LOGIN%%))"
for uid, as i intend!
and much more: i can also use simultaneously 2 bindUserDN (as expected, according to your code)
bindUserDN[]="cn=%%LOGIN%%,ou=users,dc=cmarl,dc=pt"
bindUserDN[]="uid=%%LOGIN%%,ou=users,dc=cmarl,dc=pt"
i also tried configured groups rights into LWC but without success...
my DN (group): cn=informatica,ou=Groups,dc=cmarl,dc=pt i created a group as informatica name in LWC and i'm using
searchGroupFilter="(&(objectClass=*)(cn=*)(memberUid=%%LOGIN%%))"
searchGroupProperty="cn"
but the group is not assigned to the user (memberUid)
thank you so much @laurentj :-)
hi @laurentj
i think that the plugin needs something like this for the groups:
searchBaseDN="ou=Groups,dc=cmarl,dc=pt"
what do you think about it?
@josemvm you mean, you would like a searchGroupBaseDN
property to search groups, like searchBaseDN
for users?
yes @laurentj
because the user properties have no field with a memberUid
the memberUid
is present only in the goup properties, like this:
DN: cn=informatica,ou=Groups,dc=cmarl,dc=pt
so, i think that the plugin must search the user groups from the groups (ou=Groups")... and in this case the plugin needs a searchBaseDN
...
thanks
@josemvm ok. I made this change. You now have a searchGroupBaseDN property. I also renamed searchBaseDN to searchUserBaseDN.
And ldap connection settings have been moved to profiles.ini.php. See the documentation into README.md.
many thanks @laurentj
i will try ASAP
hi @laurentj
should i set these 2 profiles in profiles.ini.php file?
[jdb:myldapdao] driver="mysqli" host= "localhost" or ldap server ip ? database="userdb" user= "admin" password="jelix" or "admin" ? persistent= on force_encoding = on
[ldap:myldapdao] hostname=10.27.3.5 or ldap://10.27.3.5 ? port=389 adminUserDn="cn=Manager,dc=cmarl,dc=pt" adminUserPassword="xxxxxxxx"
and in authldap.coord.ini.php file?
; profile to use for jDb ; profile = "jauth"
; profile to use for ldap profile="myldapdao" ldapprofile="myldapdao"
with these options i get a blank page without log errors...
For profile
, it if worked before, you don't have to change anything, and you don't have to set a new profile jdb:myldapdao
.
However, you should create a profile for ldap settings. You just have to move ldap properties like "hostname", "port", ldapAdminUserDn" and "ldapAdminPassword" to profiles.ini.php:
[ldap:myldapdao]
hostname=10.27.3.5
port=389
adminUserDn="cn=Manager,dc=cmarl,dc=pt"
adminUserPassword="xxxxxxxx"
and set ldapprofile="myldapdao"
into authldap.coord.ini.php
hi @laurentj
to debug the problem, i came back at your commit https://github.com/jelix/ldapdao-module/commit/24af788bf281a17dc63a906d52de6cb6b5a298a7
and after this commit and with the due changes/adaptations into authldap.coord.ini.php file the plugin stopped working.
should the plugin be working after this commit? i think so but it doesn't.
Hi,
I was able to switch from sqlite to postgresql for lizamp authentication backend reading the jelix docs. Very handy! From the docs I also noticed jelix support for ldap although it's not so obvious to me how to implement it. Is this sth. lizmap would support? Can I easily plugin the ldap driver to authenticate my lizmap users? What is involved to implement it?
Thanks and regards,
Thomas