I’ve been working with Discourse for a few weeks now and loving it, but the one thing I can’t get to work is OAuth2 with Microsoft Active Directory Federation Services (2016). The problem I have is that from tracing the code in the plugin on GitHub, the process is trying to make a secondary call to retrieve the user JSON Data and ADFS doesn’t like that as it’s included in the main Auth Token.
I’ve tried https://<auth_url>/adfs/userinfo and other combinations but they all error.
Has anybody managed to get this working as I’m out of ideas? I’ve taken a look at Auth0 which would work, but I want to use Discourse for an office Buy/Sell and general chat board for Employees so the cost is prohibitive.
So in theory, you can use the new discourse-openid-connect plugin. After completing the setup on the ADFS end, you just input the ‘discovery document’ URL into Discourse, along with the client id/secret. If the discovery document does not contain a “user info endpoint”, then the user information will be extracted from the JSON Web Token obtained from the “token endpoint”.
I will be adding some documentation for this new openid connect plugin this week, so please do let me know if you get it working for ADFS!
I have removed the Oauth-basic plugin and installed the OpenID as suggested and it certainly got a lot further than the OAuth one did in a single step! I am getting an error when trying to login which you may be able to advise on? I’m using my own domain account so I know that the creds are correct.
From shared/standalone/log/rails/production.log
(oidc) Setup endpoint detected, running now.
(oidc) Request phase initiated.
Started GET "/auth/oidc/callback?code=t43rNvqNsk2lyQV91F0QOg.YqkNMDtZ1ghkACQIgPZC7OK5dB4.QFwAW_4H9PkcvkZF2Oe6AU9fb7R_JnbFxia5ozlYs6qr6AJfHvLkkgOV9ConwoffwHeRf53AqXvBz5yfIb4TNBW0TWOPZJamS7yXti13hj-f0u_UQgCAMXHOYzCp4kQBH_PwUI9uvxYNU5Igc3pLiF2VaVHVtvAbrBUzPydPZ9eMbr3g-sbZPbPXb4BSnB9wgWHwpZBn3qjwBppBC7BsluC2snqQDiwNtG6t19PgcK51dpePEfAkSiKNISyxJTOj3X27H8wdAXe81sDeyrmSbcm2RROuc4vCKMgUQSY6AcK6wC_hUhZOnP-loHRGVYo0CmhX8FqS4GsQtCtxsRP89g&state=65c967333cc12c178a89d613adb02195013eabe86a047603" for 127.0.0.1 at 2018-12-03 16:20:06 +0000
(oidc) Setup endpoint detected, running now.
(oidc) Callback phase initiated.
(oidc) Authentication failure! invalid_credentials: OAuth2::Error,
Started GET "/auth/failure?message=invalid_credentials&origin=https%3A%2F%2F<ADFS_FQDN>%2Flogin&strategy=oidc" for 127.0.0.1 at 2018-12-03 16:20:06 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
Parameters: {"message"=>"invalid_credentials", "origin"=>"https://<Discourse_FQDN>/login", "strategy"=>"oidc"}
Rendering users/omniauth_callbacks/failure.html.erb within layouts/no_ember
Rendered users/omniauth_callbacks/failure.html.erb within layouts/no_ember (0.6ms)
Rendered layouts/_head.html.erb (6.0ms)
Rendered common/_discourse_stylesheet.html.erb (41.1ms)
Rendered application/_header.html.erb (0.7ms)
Completed 200 OK in 65ms (Views: 44.1ms | ActiveRecord: 12.0ms)
If this thread should be posted elsewhere please let me know ;o)
More followup! The only error in the ADFS Tracing debug log is:
UserInfoListener.ValidateAccessToken: The access token in the request doesn’t have required audience ‘urn:microsoft:userinfo’.
But the almost last entry is a success:
An OAuth Authorization Code: ‘oSTUfjxZ1ghmAJp0gfEEodZKo7o’ was successfully issued to client: ‘87c22285-8e7a-4c88-afb3-3c533031a129’ with redirectUri: …
Thanks, so it looks like there is a userinfo endpoint specified in the document. Since it is specified, the plugin will try and use it to collect metadata about the user, rather than using the data in the token. It sounds like ADFS is issuing a token which does not have permission to access the userinfo URL. That might be configurable, but I’m afraid I don’t know anything about ADFS.
If that can’t be fixed, I can add a configuration option to the plugin so that you can force the plugin to ignore the userinfo endpoint - it sounds like this could be a useful preference for other people as well.
Thanks for reviewing the document and your suggestions. I will take a look into ADFS to see if that section is protected (most likely needs unlocking through PowerShell) and if I crack it I will let you know what I needed to do for your reference. If that doesn’t turn anything up I will most likely fork your project so I can put a load of debugging logs in it to try to narrow down where it’s getting the error from ADFS.
If you do end up doing this, it would be a very welcome pull request. We have this ‘verbose logging’ functionality in the OAuth2-basic plugin behind a site setting
I’ve been doing some more work on this today but not making a whole lot of progress as this is my first foray into ROR code as I’m a .Net Developer. Whilst the logging is working it’s taking me a huge amount of time to do any debugging as I have to change a line, commit, upgrade the plugin in Discourse, try again and round and round from there.
Before I spend any more time doing that same process, is there any way to do inline debugging for a Discourse plugin as I would be used to in Visual Studio? I appreciate that there are complexities and potentially some restrictions with it being hosted in Docker, but there must be a better way. I’ve done a search on this forum but not really turned anything up, so any advice would be appreciated!
Inline debugging in an IDE is tricky to get set up. The best way is to set up a local development copy of Discourse. When developing locally, changes to code update live, so you don’t even have to restart the server! The easiest way to get started with that is:
Alternatively…
This is not ‘recommended’, but if you want to stick with making changes on your production instance, you can speed things up by getting a terminal inside the docker container
/var/discourse/launcher enter app
and then editing files directly
vi /var/www/discourse/plugins/discourse-openid-connect/......
and then restarting the server manually from within the container
I thought I was making progress then I hit against yet another problem! This time it’s to do with Cookies and it would seem that OmniAuth is trying to store the entire JWT response which is too long. To be honest it could be something to do with what I’ve done but I can’t make any further progress as this is too deep into RoR for me