Page MenuHomePhabricator

Cannot login to private wiki using BotPassword
Open, LowPublicBUG REPORT

Description

List of steps to reproduce

  • setup a private (self-hosted) wiki
  • create a bot password
  • configure user-config.py and user-password.py with the botpassword
  • python pwb.py login

What happens?

The login fails, because the login procedure attempt to retrieve the mediawiki version with an api call, but it does not have permission to do this:

WARNING: API error readapidenied: You need read permission to use this module.
WARNING: API error readapidenied: You need read permission to use this module.
ERROR: You have no API read permissions. Seems you are not logged in.
Logging in to timeseries:timeseries as Chris.blom@Ai
WARNING: API error readapidenied: You need read permission to use this module.
ERROR: You have no API read permissions. Seems you are not logged in.
ERROR: Login failed (readapidenied).
Traceback (most recent call last):
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/login.py", line 307, in login
    self.login_to_site()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/data/api.py", line 2853, in login_to_site
    below_mw_1_27 = self.site.mw_version < '1.27'
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_apisite.py", line 951, in mw_version
    mw_ver = MediaWikiVersion(self.version())
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_apisite.py", line 927, in version
    version = self.siteinfo.get('generator', expiry=1).split(' ')[1]
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 296, in get
    preloaded = self._get_general(key, expiry)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 237, in _get_general
    default_info = self._get_siteinfo(props, expiry)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 162, in _get_siteinfo
    data = request.submit()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/data/api.py", line 2009, in submit
    self._data = super().submit()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/data/api.py", line 1859, in submit
    raise pywikibot.exceptions.APIError(**result['error'])
pywikibot.exceptions.APIError: readapidenied: You need read permission to use this module.
[help: See https://wiki.timeseries.com/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; for notice of API deprecations and breaking changes.]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/chris/virtualenv/foo/bin/navi", line 223, in <module>
    action.execute()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/wiki_bot_navi/actions.py", line 167, in execute
    if not wiki.get_page(self.component).exists():
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/wiki_bot_navi/wiki.py", line 27, in get_page
    return pywikibot.Page(_get_site(), page_name)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/tools/__init__.py", line 1648, in wrapper
    return obj(*__args, **__kw)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/page/__init__.py", line 2061, in __init__
    super().__init__(source, title, ns)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/page/__init__.py", line 171, in __init__
    self._link = Link(title, source=source, default_namespace=ns)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/tools/__init__.py", line 1648, in wrapper
    return obj(*__args, **__kw)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/page/__init__.py", line 5192, in __init__
    self._defaultns = self._source.namespaces[default_namespace]
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_basesite.py", line 253, in namespaces
    self._namespaces = NamespacesDict(self._build_namespaces())
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_apisite.py", line 860, in _build_namespaces
    for nsdata in self.siteinfo.get('namespaces', cache=False).values():
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 296, in get
    preloaded = self._get_general(key, expiry)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 237, in _get_general
    default_info = self._get_siteinfo(props, expiry)
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_siteinfo.py", line 162, in _get_siteinfo
    data = request.submit()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/data/api.py", line 2009, in submit
    self._data = super().submit()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/data/api.py", line 1825, in submit
    self.site.login()
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/site/_apisite.py", line 388, in login
    if login_manager.login(retry=True, autocreate=autocreate):
  File "/home/chris/virtualenv/foo/lib/python3.9/site-packages/pywikibot/login.py", line 316, in login
    raise NoUsernameError(error_msg)
pywikibot.exceptions.NoUsernameError: Username "Chris.blom@Ai" does not have read permissions on timeseries:timeseries
CRITICAL: Exiting due to uncaught exception <class 'pywikibot.exceptions.NoUsernameError'>

The problem is that LoginManager, login_to_site, attempt to retrieve the version from mediawiki via an api call:
(See https://github.com/wikimedia/pywikibot/blob/heads%2F6.3.0/pywikibot/data/api.py#L2853, via https://github.com/wikimedia/pywikibot/blob/heads%2F6.3.0/pywikibot/data/api.py#L2853)

By adding logging I could inspect the request made to mediawiki:

Request:
uri=/api.php?action=query&meta=siteinfo%7Cuserinfo&siprop=namespaces%7Cnamespacealiases%7Cgeneral&continue=&uiprop=blockinfo%7Chasmsg&maxlag=5&format=json
body=None
headers={'Content-Type': 'application/x-www-form-urlencoded'}

Response:
response body:  {'error': {'code': 'readapidenied', 'info': 'You need read permission to use this module.', '*': 'See https://wiki.timeseries.com/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at &lt;https://lists.wikimedia.org/mailman/listinfo/

If I modify the method that does the api call (APISite.mw_version) to return a hardcoded version, the login works.
Once logged in, I can revert this change and it all just works. (Once logged in, it has permission to query the version)

What should have happened instead?:

The login procedure should query the mediawiki version in a way that does not result in the readapidenied error, or skip the query when not logged in.

Software version:

I've replicated this problem with all combinations of mediawiki-1.32 and mediawiki-1.35, pywikibot-6.1.0, and pywikibot-6.3.0

Event Timeline

Is this a WMF-hosted private wiki, or a self-hosted private wiki?

Xqt triaged this task as High priority.Jun 8 2021, 4:53 PM
Xqt added subscribers: Dvorapa, Mpaa.

These are the permission settings:

# The following permissions were set based on your choice in the installer
$wgGroupPermissions['*']['createaccount'] = true;
$wgGroupPermissions['*']['autocreateaccount'] = false;
$wgGroupPermissions['*']['edit'] = false;
$wgGroupPermissions['*']['read'] = false;

# Bot users need read access in order to function
$wgGroupPermissions['*']['bot'] = true;

I don't think it's a problem with the permissions: when i comment out the version check before the login as described, the login succeeds.

After some experimentation, i've come up with a possible fix:

  1. Make it possible to specify the mediawiki version in the family file
  2. If the mediawiki version is specified in the familiy file, use that version instead of getting it from the mediawiki server

I've also noticed that isPublic in family files is no longer used.
I found some old documentation that suggest that overriding isPublic in the family file would have a similar effect, but this no longer works: isPublic is no longer used.

I can prepare a pull request for this fix, please let me know if this approach is acceptable.

I've also tried to delay the lookup of the version until after login, but unfortunately the version is also check whenever a request is submitted, so i think it is not feasible to fix it that way.

This comment was removed by ChrisBlomTS.

I think the problem is the api.LoginManager.login_to_site code part. No further api calls should be necessary before login is either successfull or denied. A try/except clause instead of mw_version test should be made here

Ok, i've tried that, but unfortunately there are a few other places in the codebase where calls to mw_version are made:

For example here, in api.py, Request.add_defaults() via Request.submit() see:
https://github.com/wikimedia/pywikibot/blob/master/pywikibot/data/api.py#L1245-L1247

Change 699152 had a related patch set uploaded (by Xqt; author: Xqt):

[pywikibot/core@master] [bugfix] don't try to retrieve data until logged in

https://gerrit.wikimedia.org/r/699152

Change 699152 seems like a cleaner solution, i'll check if it also works for my private wiki / BotPassword case

It doesn't, the mw_version check in api.Request.add_defaults() (line 1243) still fails.

It doesn't, the mw_version check in api.Request.add_defaults() (line 1243) still fails.

Ah, during get_login_token() I think.

I can confirm it works with the latest changes

Change 699195 had a related patch set uploaded (by Xqt; author: Xqt):

[pywikibot/core@master] [IMPR] Raise a RuntimeError if a MediaWiki version is used during login

https://gerrit.wikimedia.org/r/699195

Change 699152 merged by jenkins-bot:

[pywikibot/core@master] [bugfix] don't try to retrieve data until logged in

https://gerrit.wikimedia.org/r/699152

Xqt lowered the priority of this task from High to Low.Jun 10 2021, 4:16 PM