Mattermost Peer-to-Peer Forum

ADFS SAML information users_file


#1

What is this talking about?
" For ADFS, you can use the AD/LDAP protocol to directly extract the users information and export it to a JSON file."

Assumptions in documentation… it’s just never a good idea.

Does mattermost even have a way of pulling users and their email addresses information?

All I need is a list of the users

saml_users.json with email and username right?
{
"johnsmith@email.com": “jsmith”,
"bobswagger@email.com": “bswagger”
}

and then run the command -
mattermost user migrate_auth ldap saml saml_users.json


#2

Thanks for your question @mathurin,

One of our community members has responded with the following:

 1. acronyms:

* ADFS: [Active Directory Federation Services](https://en.wikipedia.org/wiki/Active_Directory_Federation_Services)
* AD: [Active Directory](https://en.wikipedia.org/wiki/Active_Directory)
* LDAP: [Lightweight Directory Access Protocol](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
* JSON: [JavaScript Object Notation](https://en.wikipedia.org/wiki/JSON)

The cited phrase seems to originate from [here (Section "*Migrate to SAML*")](https://docs.mattermost.com/administration/command-line-tools.html). It refers to the third of the three options introduced [here](https://docs.mattermost.com/deployment/sso-saml.html).

I'd appreciate a clarification of the second question. (Pulling from where and for what purpose?)

Aforementioned section suggests that the example file and command have correct syntax, yes.

#3

I appreciate all that, and sorry, was tired and frustrated last night.

Should have said - there’s an example of creating users_file for Okta there’s an example for OneLogin… but when it comes to ADFS there’s nothing but a one line sentence - For ADFS, you can use the AD/LDAP protocol to directly extract the users information and export it to a JSON file.

Some of us that work on MM have to wear so many different hats at work, was hoping just to find a simple how-to answer in the docs rather than researching testing, etc.

No worries…


#4

@mathurin I’ll touch base with one of our engineers to see if he has insight for running the command with ADFS. Thanks for reaching out!


#5

Yes, you are right, at the time I wrote that, I though that each ADFS is more unique in terms of how to get the users data, because it depends a lot in the structure. Maybe we can create a basic example for that, similar to the other examples, and trying to have enough “variables” to deal with the most common cases. I’ll try to write something during today, or tomorrow.


#6

Here is a python example that works with openLDAP, I’ll try to test it tomorrow with AD, but I don’t know if I’ll be able to access to one AD to test it properly:

import ldap
import json
import getpass

ldap_host = input('Ldap Host (example ldap://localhost:389): ')
base_dn = input('Base DN (example dc=mm,dc=test,dc=com): ')
bind_dn = input('Bind DN (example cn=admin,dc=mm,dc=test,dc=com): ')
password = getpass.getpass('Password: ')
user_object_class = input('User object class (example iNetOrgPerson): ')
username_field = input('Username field: ')
mail_field = input('Mail field: ')

l = ldap.initialize(ldap_host)
l.simple_bind_s(bind_dn, password)
r = l.search_s(base_dn, ldap.SCOPE_SUBTREE, '(objectClass='+user_object_class+')', [username_field, mail_field])

mapping = {}
for dn, entry in r:
    if mail_field in entry and len(entry[mail_field]) >= 1 and username_field in entry and len(entry[username_field]) >= 1:
        mapping[entry[mail_field][0].decode('utf-8')] = entry[username_field][0].decode('utf-8')

with open("saml_users.json", "w") as fd:
    json.dump(mapping, fd)

#7

Dude! That’s a start thank you… I will start playing around with it tomorrow.

Thank you for the effort!


#8

@mathurin I wrote a new version more though for Active Directory, and with pagination support.

import ldap
import json
import getpass

ldap_host = input('Ldap Host (example ldap://localhost:389): ')
base_dn = input('Base DN (example dc=mm,dc=test,dc=com): ')
bind_dn = input('Bind DN (example ORGANIZATION\username): ')
password = getpass.getpass('Password: ')
user_object_class = input('User object class (example organizationalPerson): ')
username_field = input('Username field (example sAMAccountName): ')
mail_field = input('Mail field (example mail): ')

l = ldap.initialize(ldap_host)
l.simple_bind_s(bind_dn, password)
page_control = ldap.controls.libldap.SimplePagedResultsControl(True, size=1000, cookie='')
r = l.search_ext(base_dn, ldap.SCOPE_SUBTREE, '(objectClass='+user_object_class+')', [username_field, mail_field], serverctrls=[page_control])

mapping = {}
while True:
    rtype, rdata, rmsgid, serverctrls = l.result3(r)

    for dn, entry in rdata:
        if mail_field in entry and len(entry[mail_field]) >= 1 and username_field in entry and len(entry[username_field]) >= 1:
            mapping[entry[mail_field][0].decode('utf-8')] = entry[username_field][0].decode('utf-8')

    controls = [control for control in serverctrls if control.controlType == ldap.controls.libldap.SimplePagedResultsControl.controlType]
    if not controls:
        print('The server ignores RFC 2696 control')
        break
    if not controls[0].cookie:
        break
    page_control.cookie = controls[0].cookie
    r = l.search_ext(base_dn, ldap.SCOPE_SUBTREE, '(objectClass='+user_object_class+')', [username_field, mail_field], serverctrls=[page_control])

with open("saml_users.json", "w") as fd:
    json.dump(mapping, fd)

#9

Great holiday gift - thank you so much for this!