How to import SSO users?

import
sso

(Kenny Meyer) #1

I would like to import users from an existing site, which is the SSO provider, into Discourse so that I don’t have to ask them to login themselves into Discourse via SSO.

Any ideas on how to do that?


(Jeff Atwood) #2

If you have SSO configured correctly these users will magically have a Discourse account when they log in on the parent site.


(Ryan Fox) #3

That’s not true… The accounts in Discourse aren’t created until you hit the login button. If you have SSO configured correctly, they will magically have a Discourse account when they press the login button in Discourse.


Is it required to import users when using SSO?
(Michael Downey) #4

Yes we’re in the same boat. The Discourse SSO code we used only creates the account the first time the user hits the blue “Sign In” (yes I’m living in the past voluntarily) button.

We’d love a way for their Discourse account to be automatically created in the background by the identity site’s application at the same time when the account is created in the LDAP directory.

If we had this working, then we could take a single pass through our existing users and create accounts as necessary. Then the two systems should stay in sync and everyone would always have a Discourse account.


(Ryan Fox) #5

So, I think it’s possible to just create a user with the API normally, and as long as the email address matches the one you’d use with SSO, the SSO record will get created the first time they login to DIscourse. The problem with that is that you miss out on auto username generation. If your username scheme doesn’t exactly match Discourse’s, you have to handle cases where Discourse will reject the username, and also deduplicate if there are collisions. (ie: if you have a user named foo.bar, the obvious transformation is to foo_bar, but that Discourse username might already be taken)

On my site, it’s possible for an admin to impersonate another user. Using this, I was able to write a script that logs in as an admin user, impersonates the target user, and then accesses the Discourse SSO URL. This is enough to create the user automatically, letting Discourse handle the username issues.

Note: This will trigger welcome emails to all of the users you create this way. (I accidentally sent out 300 emails, inviting people to join my test Discourse instance. :weary:)


(Michael Downey) #6

Very cool – would love to see a scrubbed version of this if you’re willing to share. :smile:


(Ryan Fox) #7

Sure. It’s essentially just this Python script:

import requests
import urllib

# Session takes care of managing the cookies between requests, etc.
session = requests.Session()

username = 'foo.bar'

r = session.post('https://mysite.com/login/', data={'username': 'admin_user', 'password': 'password123'})

# Raise an exception if we get a 400- or 500-level response code.
r.raise_for_status()

r = session.get('https://mysite.com/admin/become-user/%s/' % urllib.quote(username))
r.raise_for_status()

r = session.get('https://forum.mysite.com/session/sso')
r.raise_for_status()

(Jeff Atwood) #8

Turn on the “disable all emails” site setting before doing this kind of stuff.


(Michael Downey) #9

So I was staring at your script for several minutes a while trying to figure out what you were doing with http://discourse.example.com/admin/become-user/ … then I realized your example’s “mysite.com” is your user authority, not Discourse. :slight_smile:

Anyway, if anyone else has an idea about how to easily fire off mass user creation/import from the Discourse side (API?) I know it’d be helpful for us. Not sure about @kennym or if the above script worked for him.

I tried the below but get an almost-useful response of {"success":false,"message":"You have not completed all the user fields"} (what are they?).

curl -X POST --data "name=Tester&username=testuserid&email=tester@example.com&password=testpw&active=true&api_key={APIKEY}&api_username=adminuser" https://discourse.example.org/users

(Ryan Fox) #10

It looks like there’s also a challenge and a password_confirmation value you have to send. Look at how pydiscourse does it: pydiscourse/client.py at master · tindie/pydiscourse · GitHub


(Sigurður Guðbrandsson) #11

You can use the API by either using the ruby gem here

or just do a simple curl post like so:

curl -X POST --data "name=dave&username=dave&email=dave@example.com&password=P@ssword&active=true" http://localhost:3000/users?api_key=test_d7fd0429940&api_username=test_user

As for usernames, just assign a random username and allow SSO to override it, like so:


Synchronizing Changes for SSO users