operations
operations copied to clipboard
Add osm.org authentication to Wiki
PluggableAuth looks like a suitable extension authenticating users using OAuth from osm.org to the Wiki.
You're probably going to have to read into the specifics on your own since the various options for how users can log in can be a bit confusing.
Here is an example of a Wiki that uses it.
The users on osm.org and wiki are not 1:1 matched. Any proposal to resolve the discrepancy?
That is basically why the idea has been deemed a non-starter in the past.
The extension matches users that have the same username/email on osm.org and the wiki (not sure if both or just 1).
If users want to "link" their accounts, they're going to have to make sure these are the same.
Fortunately users can change their username and email on the wiki and osm.org, so they get to decide what email/account they want to link.
So how does it stop me taking over a wiki account by creating an OSM account with the same name?
That's why I think both have to be the same.
That was my point, if just have the same name is all it takes then I can create an account call JohnBrown on OSM and then login to the wiki as JohnBrown even if there is already an account called that which isn't mine?
Oh no, what I meant is that both the osm.org and wiki email and username have to be the same.
I wonder if there’s an option for an already logged on wiki user to associate their account with an external identity provider, such as the osm.org website. Of course the user would also have to log on to osm.org to establish that link.
I think user names don’t have to match in that case, as long as a wiki user has an external alias identity. This might also include other trustworthy identity providers.
What if I wanted to create a bot account on Wiki - will I have to create an OSM account for it first?
What if I wanted to create a bot account on Wiki - will I have to create an OSM account for it first?
No. You can continue to create individual accounts on both osm.org and the Wiki.
I wonder if there’s an option for an already logged on wiki user to associate their account with an external identity provider, such as the osm.org website.
That's what this extension does.
I think user names don’t have to match in that case, as long as a wiki user has an external alias identity. This might also include other trustworthy identity providers.
What's an external alias identity? Just any account?
He's talking about a system like osm.org uses, where if you setup login with Google or Facebook or whatever we store the identity of that account so that you can login with it without your email and/or username having to match.
In other words the user has to explicitly associate the accounts and cause a link to be stored rather than an implicit link based on name and email.
What really happens is that a button below the normal "log in" button on the wiki will display with the label "Log in with OpenStreetMap.org"
The user can then click that and the external identification OAuth window (idk entirely how OAuth works) appears.
Whatever the user logins as via that window, the OAuth client returns the username and email of that account to the wiki. If an account with that username and email exists on the Wiki, they are logged-in.
Users can still log in with their normal Wiki username and password in the current input boxes on the login page on the Wiki if they want to.
So what you're describing here is essentially the same thing I've demoed for Discourse: https://user-images.githubusercontent.com/5842757/96035123-e1a1e700-0e62-11eb-9f05-fa92e8751ad0.gif I've tried the same thing on a test wiki, and it wasn't all that smooth sailing.
Still this doesn't address the issue of associating osm and wiki accounts, when we can't rely on a matching name/email.
Well he is suggesting that we do rely on matching and that people can change their names on one or both systems to achieve that is necessary.
I would very much prefer an explicit link though I have to say.
First question i would have is: Does mediawiki support all usernames we have in OSM. OSM has been very relaxed with user naming so there may be pitfalls with non-ascii, utf8-emoji, control character etc names.
@flohoff : it doesn't matter, we won't be matching by user names anyway. That's the idea of having explicit links.
Example: Wiki user xyz
with wiki user id 5678 has an explicit association to their OSM account with uid = 123456 (which corresponds to display_name abc
).
Wikimedia: For your plan to synergize OSM.org and wiki.OSM.org it would be great to consider Wikimedia-accounts too :-) (Wikipedia, Commons, Wikidata, ... as global Wikimedia user account) This would be a great synergy for both projects!
By script you can ask:
- New OSM users, if he has a Wikipedia account and would like to use it for OSM and the OSM-Wiki too?
- Existing OSM users, if he would like to merge his OSM account to the Wikipedia account? or if he prefer to merge his Wikipedia account to the OSM account? (if 2 times "no", he will keep different logins) (if "yes" but the other account is already used by an other user, he can create an new account for OSM and Wikipedia)
So now that OAuth2 is established and Discourse is almost up and running, it might be the best time look into this issue again.
Added the "help-wanted" label. I can support any tests anyone wants to run.
Challenges we would likely need to solve to implement this ticket:
- osm.org "Display Names" (aka Usernames) are not fixed, we deal with this on community.osm.org by setting the name on community.osm.org on each user login and use the UserID from osm.org as the unique key. The oauth is specially blessed for community.osm.org to be able to access user email address.
- Many usernames for wiki.osm.org do not match the same user on osm.org, how do we workaround / resolve this?
- How would the process to migrate wiki users to osm.org based logins work? (Technically and practically)
- Maintainability going forward, if custom code is used, it needs to be maintained going forward.
Maybe we could have a brainstorming video call sometime to draw out a plan?
You can if you want just allow the names to be different, as help.osm.org does and as osm.org does if you use Google or Facebook to login.
You just store the identity on the remote system as an attribute of the account, and when someone proves control of that identity you let them login to that account.
Last time I looked for some mediawiki plugins, I couldn't find anything similar to the approach we're using for Discourse.
I wonder if some development effort on the Rails port would be acceptable, if that's eliminating the need for a custom wiki plugin. We might check if https://www.mediawiki.org/wiki/Extension:OpenID_Connect could be an option for us.
I played a bit with https://github.com/doorkeeper-gem/doorkeeper-openid_connect to enable Openid connect support on the Rails port. Most of the installation worked out of the box (as far as you can call this working). I'm documenting a few changes I did to the config. For sure this needs some more work. I believe this could be used a starting point to enable OpenID Connect mediawiki extension. I haven't tried this out end-to-end yet, though.
Setting up doorkeeper-openid_conect gem
After rails generate doorkeeper:openid_connect:install
, I added Rails.application.reloader.to_prepare do to the doorkeeper_openid_connect.rb file, otherwise the migration step would bail out.
SAFETY_ASSURED=1 was used to silence an otherwise unhappy strong_migration.
config/initializers/doorkeeper_openid_connect.rb:
# frozen_string_literal: true
Rails.application.reloader.to_prepare do
Doorkeeper::OpenidConnect.configure do
issuer do |resource_owner, application|
'http://localhost:3000'
end
signing_key <<~KEY
-----BEGIN RSA PRIVATE KEY-----
[add private key...]
-----END RSA PRIVATE KEY-----
KEY
subject_types_supported [:public]
resource_owner_from_access_token do |access_token|
# Example implementation:
User.find_by(id: access_token.resource_owner_id)
end
auth_time_from_resource_owner do |resource_owner|
# Example implementation:
#resource_owner.current_sign_in_at
end
reauthenticate_resource_owner do |resource_owner, return_to|
# Example implementation:
# store_location_for resource_owner, return_to
# sign_out resource_owner
# redirect_to new_user_session_url
end
# Depending on your configuration, a DoubleRenderError could be raised
# if render/redirect_to is called at some point before this callback is executed.
# To avoid the DoubleRenderError, you could add these two lines at the beginning
# of this callback: (Reference: https://github.com/rails/rails/issues/25106)
# self.response_body = nil
# @_response_body = nil
select_account_for_resource_owner do |resource_owner, return_to|
# Example implementation:
# store_location_for resource_owner, return_to
# redirect_to account_select_url
end
subject do |resource_owner, application|
# Example implementation:
resource_owner.id
# or if you need pairwise subject identifier, implement like below:
# Digest::SHA256.hexdigest("#{resource_owner.id}#{URI.parse(application.redirect_uri).host}#{'your_secret_salt'}")
end
claims do
claim :preferred_username, scope: :openid do |resource_owner, scopes, access_token|
# Pass the resource_owner's preferred_username if the application has
# `profile` scope access. Otherwise, provide a more generic alternative.
resource_owner.display_name
end
end
end
end
I added a new privileged scope 'openid' (translation for en.oauth.scopes.openid should also be added):
diff --git a/lib/oauth.rb b/lib/oauth.rb
index 7ff2ba8b4..1c7b38636 100644
--- a/lib/oauth.rb
+++ b/lib/oauth.rb
@@ -1,6 +1,6 @@
module Oauth
SCOPES = %w[read_prefs write_prefs write_diary write_api read_gpx write_gpx write_notes].freeze
- PRIVILEGED_SCOPES = %w[read_email skip_authorization].freeze
+ PRIVILEGED_SCOPES = %w[read_email skip_authorization openid].freeze
class Scope
attr_reader :name
Skipping the suggested view generation (rails generate doorkeeper:views
) and added the nonces field here instead:
diff --git a/app/views/oauth2_authorizations/new.html.erb b/app/views/oauth2_authorizations/new.html.erb
index 971e0e20a..ac9c7c6c5 100644
--- a/app/views/oauth2_authorizations/new.html.erb
+++ b/app/views/oauth2_authorizations/new.html.erb
@@ -18,6 +18,7 @@
<%= f.hidden_field :state, :value => @pre_auth.state %>
<%= f.hidden_field :response_type, :value => @pre_auth.response_type %>
<%= f.hidden_field :scope, :value => @pre_auth.scope %>
+ <%= f.hidden_field :nonce, :value => @pre_auth.nonce %>
<%= f.hidden_field :code_challenge, :value => @pre_auth.code_challenge %>
<%= f.hidden_field :code_challenge_method, :value => @pre_auth.code_challenge_method %>
<%= f.primary t(".authorize") %>
@@ -30,6 +31,7 @@
<%= f.hidden_field :state, :value => @pre_auth.state %>
<%= f.hidden_field :response_type, :value => @pre_auth.response_type %>
<%= f.hidden_field :scope, :value => @pre_auth.scope %>
+ <%= f.hidden_field :nonce, :value => @pre_auth.nonce %>
<%= f.hidden_field :code_challenge, :value => @pre_auth.code_challenge %>
<%= f.hidden_field :code_challenge_method, :value => @pre_auth.code_challenge_method %>
<%= f.submit t(".deny") %>
Adjusted routes to point to /oauth2 instead
diff --git a/config/routes.rb b/config/routes.rb
index e45d56701..b1e69dce3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,4 +1,5 @@
OpenStreetMap::Application.routes.draw do
+ use_doorkeeper_openid_connect :scope => "oauth2"
use_doorkeeper :scope => "oauth2" do
controllers :authorizations => "oauth2_authorizations",
:applications => "oauth2_applications",
Result
In the end, I used some demo OpenId connect client, and got the following result on http://localhost:3000/oauth2/userinfo
{
"sub": "2",
"preferred_username": "mmd3"
}
http://localhost:3000/.well-known/openid-configuration contents:
{
"issuer": "http://localhost:3000",
"authorization_endpoint": "http://localhost:3000/oauth2/authorize",
"token_endpoint": "http://localhost:3000/oauth2/token",
"revocation_endpoint": "http://localhost:3000/oauth2/revoke",
"introspection_endpoint": "http://localhost:3000/oauth2/introspect",
"userinfo_endpoint": "http://localhost:3000/oauth2/userinfo",
"jwks_uri": "http://localhost:3000/oauth2/discovery/keys",
"scopes_supported": [
"read_prefs",
"write_prefs",
"write_diary",
"write_api",
"read_gpx",
"write_gpx",
"write_notes",
"read_email",
"skip_authorization",
"openid"
],
"response_types_supported": [
"code"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"grant_types_supported": [
"authorization_code"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"claim_types_supported": [
"normal"
],
"claims_supported": [
"iss",
"sub",
"aud",
"exp",
"iat",
"preferred_username"
]
}
Mediawiki plugin seems to support user migration by email address, although I'm not sure if that's opening up some loophole. Migrating by username makes absolutely no sense.
As the plugin supports both realname, and email, we could add some more claims to the doorkeeper_openid_connect config:
normal_claim :email, scope: :read_email do |resource_owner, scopes, access_token|
resource_owner.email
end
normal_claim :name, scope: :openid do |resource_owner, scopes, access_token|
resource_owner.display_name
end
User details will now include those two additional claims as:
{
"sub": "1",
"email": "some email address @ xyz . abc",
"name": "mmd2",
"preferred_username": "mmd2"
}
I believe this now includes all details the mediawiki extension is asking for.
I put together a small video highlighting the end-to-end process. I believe there's a good chance that this might actually work...
🎥 Demo time (screencast)
mmd2 has an already existing wiki user with a matching email address.
LocalSettings.php additions (demo only!):
$wgPluggableAuth_EnableLocalProperties = true;
$wgPluggableAuth_EnableLocalLogin = true;
$wgPluggableAuth_ButtonLabel = 'Log in via OpenStreetMap';
$wgOpenIDConnect_Config['http://localhost:3000/'] = array(
'clientID' => '...',
'clientsecret' => '...',
'scope' => [ 'read_prefs', 'openid', 'read_email' ],
'verifyHost' => false,
'verifyPeer' => false
);
$wgOpenIDConnect_MigrateUsersByEmail = true;
wfLoadExtension( 'PluggableAuth' );
wfLoadExtension( 'OpenIDConnect' );
OAuth2 application - Redirect URIs on Rails port also included http://localhost/mediawiki/index.php?title=Special:PluggableAuthLogin
mediawiki.openid_connect table stores a link between wiki user id, and the uid we use on the rails port:
select * from mediawiki.openid_connect;
oidc_user | oidc_subject | oidc_issuer
-----------+--------------+------------------------
1 | 1 | http://localhost:3000/
3 | 2 | http://localhost:3000/
4 | 3 | http://localhost:3000/
5 | 6 | http://localhost:3000/
7 | 7 | http://localhost:3000/
8 | 8 | http://localhost:3000/
10 | 9 | http://localhost:3000/
There has been much wiki discussion about removing barriers from the wiki recently. I also would like to see a "Log in via openstreetmap.org" on the OSM wiki as soon as possible. Since it seemed like getting the Rails port to support OpenID Connect wasn't going anywhere (no reply here on if that's acceptable and no issue over at the website repo), I looked into getting it to work with the existing OAuth 2.0 API. As it turns out the OAuth 2.0 plugin for PluggableAuth doesn't support any migration mechanism suitable for us. I looked into PluggableAuth but found its documentation, API design and integration into MediaWiki to be lacking, so I ended up writing my own MediaWiki extension: RedirectAuth.
You can try it out at https://demo-wiki.push-f.com/.
Note that unlike the previously suggested OIDC extension my extension does not perform mapping per email addresses but instead lets users link an existing wiki account with their OSM account no matter which email addresses they have configured.
Note that I have already asked the community for feedback for my extension on the talk@ mailing list and the community forum.
@not-my-profile : can you maybe write a few words on how you have planned to support your extension going forward? How about translating messages to other languages?
As mentioned on the community site, I had a strong focus to use an officially supported wiki extension and avoid any custom code (see my comment from Aug 5). Due to the extreme shortage of knowledgable MediaWiki folks around here, this seemed like the least risky option, although user experience may not be as good as it could be.
Then of course: Implementing OpenID Connect on the Rails port is also beneficial for other applications, not only the Wiki.
I would maintain it in my self-hosted repo and document it on the mediawiki.org wiki (I have not yet done so because I don't want to spend time writing documentation if I don't yet know if the extension will actually be used by the OSM wiki). I'd answer questions about the extension on its talk page at mediawiki.org as well as be available for contact via email for the operations working group. I think for translations I would sign up my extension at translatewiki.net (which is used by MediaWiki itself as well as hundreds of MediaWiki extensions).
Any chance @Firefishy, @tomhughes and @pnorman could look at this issue in one of the next OWG meetings and discuss whether the approach suggested by @not-my-profile would work at all for the OSM wiki?
I saw that you already started exploring evaluation criteria for wiki addons in #785. Maybe this could be a good opportunity to add a bit more detail there as well.
Why am I bringing this up now? A board member has recently mentioned in a conference talk that all these nice ideas on the OSM Top Ten Task list are impossible to implement (OSM.org authentication to the Wiki being one of them). I think that's not quite accurate.
What exactly do you want OWG to discuss? I've only skimmed this thread but it seems to be OpenID Connect based which is not something osm.org support currently.
In any case it's not clear that there's anything here that needs a policy decision and that couldn't be actioned as a normal pull request proposing a change to the wiki if it's just a question of installing an extension?