MeshCentral
MeshCentral copied to clipboard
LDAP Improvement
Grettings
I saw your video about LDAP Integration with Meshcentral and commented it. you reply to suggest here for everyone to comment:
I have some question/improvement
Actually Meshcentral search for any users in the domain and allow everyone who have a account to login -> Can we specify an security group who the user need to be bound to allow the conexion (attribute MemberOf "Meshcentral Users" on LDAP user account for example) So if I try to connect with a account who doesn't member of "Meshcentral Users" we got an access denied that can restrain the access only for IT services for example
-> Also we could use names of MemberOf to access directly on DeviceGroup : for example If i'm member of "Windows_Servers" I have access to the Device Group "Windows_Servers" but not "Linux_Servers"
For managing the permission instead using Internal Users we could use LDAP Distinguished Name to identify the User or Group object from the group permission page for example
-> Last thing : Actually an domain user account and password is writed as plaintext in the config file that could be a security issue on some case I suggest to keep alive a administrator local account like "LDAP-admin" and we can login to meshcentral webpage with this special account to provide the LDAP credential (for renew or setup) and meshcentral store it encrypted in this internal database this page can also allow to try the ldap connexion with debug output
Thanks you sorry for typos, English is not my native language
I just checked in the first part of the request. In v1.0.71, you can add this to the domain section of the config.json:
{
"settings": {
"Cert": "central.mesh.meshcentral.com",
"Postgres": {
"user": "postgres",
"password": "tools",
"port": 5432,
"host": "localhost"
},
"Port": 443,
"RedirPort": 80
},
"domains": {
"": {
"title": "MeshCentral",
"auth": "ldap",
"ldapUserName": "{{{givenName}}} {{{sn}}}",
"ldapUserBinaryKey": "objectSid",
"ldapUserEmail": "mail",
"ldapUserRealname": "{{{givenName}}} {{{sn}}}",
"ldapUserPhoneNumber": "telephoneNumber",
"ldapUserImage": "thumbnailPhoto",
"ldapUserGroups": "memberOf", <------
"ldapUserRequiredGroupMembership": [ "CN=Domain Admins,CN=Users,DC=vprodemo,DC=com" ] <------
}
}
}
The ldapUserRequiredGroupMembership
will check that a new is a member of one of the specified user groups to allow login. The 'ldapUserGroups' has the default of 'memberOf' so you don't need to specify it if this is the correct value.
Ok, checked in a big change on LDAP. MeshCentral will now automatically create user groups that match a user's LDAP "memberOf" groups. It will then auto-join/remove users from these LDAP matching groups each time the users logs in.
So, you now see a bunch of user groups that users are part of. You can then assign permissions to device groups or individual devices to these groups. This will be in v1.0.71. Let me know if it works once it's published.
For the 3rd request on LDAP password, open a new issue for that one. Each issue should be for one item, otherwise I end up with never ending issues. Thanks.
Hello @Ylianst
That was quick 👍 I will open a other issue for the password
However I see already some issue now for the 2nd one :
- If meshcentral autocreate LDAP groups who match "MembersOf" array of an users when he log in it will become very wild quickly on larger network : a single user can be member of 100+ groups (for accessing Meshcentral, for each network storage folder write or read permission, other apps...) and can exist 10k+ groups in the domain : they will exist in meshcentral and they're useless because no permission defined. (fun fact, some windows applications or third party application start to have some authentications/permissions bugs when a single user have 230+ entry in MemberOf array)
For example on your screenshot we can see "Schema Admins" : that a security group very specifics for managing the domain architecture and should not be used in thirds apps and so be present here. (you got it because you logged as full domain "Administrator" account)
I think 3 way to solve it :
->We auto-create the group if the specified string search is present on the group DistinguedName for example
LdapGroupSearchString = "Meshcentral"
CN=Win-Server,OU=Meshcentral groups,DC=vprodemo,DC=com
will be autocreated
CN=Meshcentral Win-Server,CN=Users,DC=vprodemo,DC=com
will be autocreated
CN=Administrators,CN=Users,DC=vprodemo,DC=com
will not be created
->From Meshcentral group webpage : When you create a group you can query the LDAP to gets list of object and you select the one you want
->The easiest way (I think) : We create groups manually on Meshcentral Groups tabs page but we fill the GroupName with the LDAP DistinguedName of the group and the Users AutoJoin/AutoLeave if member or not of this groups when login (same as your build v1.0.71). -> -> for batch creation (if need to make 100 groups in once) why not submit a TXT/CSV file with a list of one DistinguedName for each line of the file
Thanks you in advance
Ohhh dear. Ok, I don't have to pick one of these, I can implement many of these solutions. I can add the auto-create on search string easily. I will do that tomorrow.
Ohhh dear. Ok, I don't have to pick one of these, I can implement many of these solutions. I can add the auto-create on search string easily. I will do that tomorrow.
Another suggestion is the way that APACHE GUACAMOLE works (if it'll be usefull please let me know to open it as a feature request).
If it's possible to be defined any access on LDAP directly. One way is by using a new schema, another way is by using already defined attributes.
The related link for LDAP schema is: https://guacamole.apache.org/doc/gug/ldap-auth.html#ldap-auth-schema
in which I have also prepared the active directory schema (command: ldifde -i -f c:[PATH]\guacSchema.ldif -b Administrator example [password] -k -j . -c "CN=Schema,CN=Configuration,DC=example,DC=net")
#Attribute definitions
dn: CN=guacConfigParameter,CN=Schema,CN=Configuration,DC=example,DC=net
changetype: ntdsschemaadd
objectClass: top
objectClass: attributeSchema
cn: guacConfigParameter
attributeID: 1.3.6.1.4.1.38971.1.1.2
attributeSyntax: 2.5.5.12
isSingleValued: FALSE
adminDisplayName: guacConfigParameter
adminDescription: guacConfigParameter
oMSyntax: 64
searchFlags: 1
lDAPDisplayName: guacConfigParameter
systemOnly: FALSE
dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-
dn: CN=guacConfigProtocol,CN=Schema,CN=Configuration,DC=example,DC=net
changetype: ntdsschemaadd
objectClass: top
objectClass: attributeSchema
cn: guacConfigProtocol
attributeID: 1.3.6.1.4.1.38971.1.1.1
attributeSyntax: 2.5.5.12
isSingleValued: FALSE
adminDisplayName: guacConfigProtocol
adminDescription: guacConfigProtocol
oMSyntax: 64
searchFlags: 1
lDAPDisplayName: guacConfigProtocol
systemOnly: FALSE
dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-
# Classes
dn: CN=guacConfigGroup,CN=Schema,CN=Configuration,DC=example,DC=net
changetype: ntdsschemaadd
objectClass: top
objectClass: classSchema
cn: guacConfigGroup
governsID: 1.3.6.1.4.1.38971.1.2.1
rDNAttID: cn
adminDisplayName: guacConfigGroup
adminDescription: guacConfigGroup
objectClassCategory: 1
lDAPDisplayName: guacConfigGroup
name: guacConfigGroup
systemOnly: FALSE
subClassOf: groupOfNames
mayContain: guacConfigParameter
mustContain: guacConfigProtocol
dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-
and how to add each configuration (command: ldifde -i -f guacUser.ldif):
DN: CN=PC1,OU=GUACAMOLE,DC=example,DC=net
changetype: add
CN: PC1
objectClass: guacConfigGroup
objectClass: groupOfNames
guacConfigProtocol: rdp
guacConfigParameter: color-depth=32
guacConfigParameter: domain=EXAMPLE
guacConfigParameter: enable-wallpaper=true
guacConfigParameter: password=${GUAC_PASSWORD}
guacConfigParameter: resize-method=display-update
guacConfigParameter: security=nla
guacConfigParameter: ignore-cert=true
guacConfigParameter: username=${GUAC_USERNAME}
guacConfigParameter: hostname=PC1.example.net
member: CN=user1,OU=User Account,DC=example,DC=net
Ok, I just added a way to filter what LDAP membership groups will be synced with MeshCentral user groups.
{
"settings": {
"Cert": "central.mesh.meshcentral.com",
"Port": 443,
"RedirPort": 80
},
"domains": {
"": {
"title": "MeshCentral",
"auth": "ldap",
"ldapUserGroups": "memberOf",
"ldapSyncWithUserGroups": { "filter": [ "CN=Enterprise Admins" ] },
"ldapUserRequiredGroupMembership": null
}
}
}
The ldapSyncWithUserGroups
key will now be false
by default, you can put:
"ldapSyncWithUserGroups": true
To sync all user groups, or:
"ldapSyncWithUserGroups": { "filter": [ "strings1", "string2", "string3" ] },
To sync some groups. If a LDAP group matches one of the strings, the group is synchronized with a MeshCentral user group.
This will be in MeshCentral v1.0.72.
I am not the OP but updated to v1.0.72 and ldapSyncWithUserGroups": false works well. Originally the User's AD Groups Imported automatically into mesh creating them, I had to update, then add that Line setting to False. Started the System, and then wait for all Mesh LDAP Users to log in before I could delete the groups. Once all Mesh Users logged in, it revoked the group membership from the user (in the logs), I was then able to delete the erroneous groups.
Also forgot to note, the ldapUserRequiredGroupMembership works well - I did run into an issue where a basic LDAP Account in Active Directory could NOT read another users Group Membership so the error message was "Access is Denied" at login. In my case, we have a Help Desk Access Group that we had to assign to the Mesh LDAP Account so it could read MemberOf Assignments of a user. This may or may not be an issue for someone else depending on how locked down their Active Directory Environment is.
I have the opposite issue with 1.0.72. Current configuration:
"auth": "ldap",
"ldapOptions": {
"url": "ldap://[IP]:389/",
"tlsOptions": { "rejectUnauthorized": false },
"bindDN": "cn=..",
"bindCredentials": "..",
"searchBase": "dc=..",
"searchFilter": "(sAMAccountName={{username}})",
"reconnect": true
},
"ldapUserName": "sAMAccountName",
"ldapUserKey": null,
"ldapUserBinaryKey": "objectSid",
"ldapUserEmail": "mail",
"ldapUserGroups": "memberOf",
"ldapUserRequiredGroupMembership": null,
"_ldapUserRequiredGroupMembership": [ "CN=.." ],
"_ldapSyncWithUserGroups": true,
"ldapSyncWithUserGroups": { "filter": [ "Group1" ] },
Also trying to find if it's possible the groups to appears with groupname only without the CN=
Everything I tried with ldapUserRequiredGroupMembership I get the error: LDAP: Denying login to a user that is not a member of a LDAP required group.
The Required Group Membership should look like this: "ldapUserRequiredGroupMembership": [ "CN=XXXX,OU=XXXXX,OU=XXXXX,DC=DOMAIN,DC=LOCAL" ],
And the user that you log into Mesh with should be a member of that. Depending on your AD Environment (if thats what your using), the LDAP Account specified with bindDN needs access to be able to read the users MemberOf Groups.
You can test that by running powershell as RUNAS the bindDN account, and Query AD with Get-ADUser -Identity MeshUser -Properties * | Select Member, if it returns only {}, your bindDN Account cant read the memberof groups and will need to be delegated more access so it can authenticate that the person trying to login is allowed to. (should be a Star infront of member and behind but cant get formatting correct.)
The Required Group Membership should look like this: "ldapUserRequiredGroupMembership": [ "CN=XXXX,OU=XXXXX,OU=XXXXX,DC=DOMAIN,DC=LOCAL" ],
And the user that you log into Mesh with should be a member of that. Depending on your AD Environment (if thats what your using), the LDAP Account specified with bindDN needs access to be able to read the users MemberOf Groups.
You can test that by running powershell as RUNAS the bindDN account, and Query AD with Get-ADUser -Identity MeshUser -Properties * | Select Member, if it returns only {}, your bindDN Account cant read the memberof groups and will need to be delegated more access so it can authenticate that the person trying to login is allowed to. (should be a Star infront of member and behind but cant get formatting correct.)
I just tried it, every memberOf is shown (it's AD). Something else is happening.
Two Ideas:
The User that you are logging into Mesh is added to the same Group specified as ldapUserRequiredGroupMembership? #2 - The Searchbase, is it high enough levels up that it can see both the ldapUserRequiredGroupMembership and the Actual User Logging in? If the SearchBase is too narrow, it may not be able to find the user or group if they are seperated in different OU's.
Yes, it's included in the ldapUserRequiredGroupMembership and there are about 30000 users on AD. If I remember correctly, in other cases I used something that's every check were about 1000 per per time, so I have to find it..
Two Ideas:
The User that you are logging into Mesh is added to the same Group specified as ldapUserRequiredGroupMembership? #2 - The Searchbase, is it high enough levels up that it can see both the ldapUserRequiredGroupMembership and the Actual User Logging in? If the SearchBase is too narrow, it may not be able to find the user or group if they are seperated in different OU's.
I have moved the ldapUserRequiredGroupMembership to the same OU and changed the searchBase on this OU. Now it works, but it could be useful to be used the entire domain. An example is on Apache Guacamole (I mistyped Veyon before) we're using for students, we have:
ldap-user-base-dn: dc=example,dc=domain,dc=com ldap-config-base-dn: OU=GUAC1,OU=GUACAMOLE,DC=example,DC=domain,DC=com ldap-max-search-results: 1000
that I couldn't found yet if it's possible with ldapauth-fork
@si458 can close