Jump to content

Topic on Extension talk:LDAPAuthentication2

{"clientlogin":{"status":"FAIL","message":"The supplied credentials could not be authenticated.","messagecode":"authmanager-authn-no-primary"}}

33
Uckelman (talkcontribs)

I'm converting from the old LdapAuthentication extension to the PluggableAuth/LDAPProvider/LDAPAuthentication2 stack. Using the login page directly, I'm able to log in successfully with my LDAP credentials. When I use the MW REST API to log in via the clientlogin action, however, I get this error message:

{"clientlogin":{"status":"FAIL","message":"The supplied credentials could not be authenticated.","messagecode":"authmanager-authn-no-primary"}}

This happens after I've successfully called api.php?action=query&meta=tokens&type=login&format=json to get a login token, which I'm sending back as part of the login request. I've also checked that I'm returning the wikidb_session cookie in the clientlogin request headers. The login action I used to use is now deprecated for "main-account login", and main account login is what I need here since the cookies sent back after login are supposed to be handed back to my site's SSO system.


What am I doing wrong here?

Osnard (talkcontribs)

Hi! Have you set up the "default domain"? Or have you specified the domain to log into in your API request?

@Cindy.cicalese This sounds like it is related to Extension:PluggableAuth. Do you have an idea?

Uckelman (talkcontribs)

I have this in my LocalSettings.php:$LDAPProviderDefaultDomain = "LDAP";

and in my /etc/mediawiki/ldapprovider.json I have

{
  "LDAP": {
    "connection": {
      "server": "localhost",
      ... more stuff ...
    }
  }
}

I can see manual logins talking with slapd (and those logins succeed), so I have some evidence that my ldapprovider.json is being used.

Is that sufficient for setting up a default domain?

Cindy.cicalese (talkcontribs)

My understanding is that you should be able to use Manual:Bot passwords to login using the API to a wiki running PluggableAuth.

Uckelman (talkcontribs)

Quoting the bot passwords docs: "Clients using bot passwords can only access the API, not the normal web interface." That makes it sounds like the cookies I would get from a bot password login would not work for passing them back to a user with a web browser. Am I misreading it?

Uckelman (talkcontribs)

Here's an additional thing I hadn't noticed: If I hit /wiki/api.php?action=query&meta=authmanagerinfo&amirequestsfor=login (and I have all the debugging facilities I can find turned on) I see this:

[error] [YMel0U-dIvymGFJtpDu3kAAAAMU] /wiki/api.php?action=query&meta=authmanagerinfo&amirequestsfor=login   ErrorException from line 343 of /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php: PHP Notice: Undefined index: label
[exception] [YMel0U-dIvymGFJtpDu3kAAAAMU] /wiki/api.php?action=query&meta=authmanagerinfo&amirequestsfor=login   TypeError from line 76 of /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php: Argument 3 passed to ApiAuthManagerHelper::formatMessage() must be an instance of Message, null given, called in /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php on line 343

I guess this query is supposed to return the names of additional fields (such as username and password) that the auth provider will take from clientlogin?

Also a stacktrace in the query output:

{
    "error": {
        "code": "internal_api_error_TypeError",
        "info": "[YMel0U-dIvymGFJtpDu3kAAAAMU] Exception caught: Argument 3 passed to ApiAuthManagerHelper::formatMessage() must be an instance of Message, null given, called in /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php on line 343",
        "errorclass": "TypeError",
        "*": "TypeError at /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php(76)\n#0 /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php(343): ApiAuthManagerHelper->formatMessage()\n#1 /usr/share/mediawiki/includes/api/ApiAuthManagerHelper.php(304): ApiAuthManagerHelper->formatFields()\n#2 /usr/share/mediawiki/includes/api/ApiQueryAuthManagerInfo.php(88): ApiAuthManagerHelper->formatRequests()\n#3 /usr/share/mediawiki/includes/api/ApiQuery.php(263): ApiQueryAuthManagerInfo->execute()\n#4 /usr/share/mediawiki/includes/api/ApiMain.php(1593): ApiQuery->execute()\n#5 /usr/share/mediawiki/includes/api/ApiMain.php(529): ApiMain->executeAction()\n#6 /usr/share/mediawiki/includes/api/ApiMain.php(500): ApiMain->executeActionWithErrorHandling()\n#7 /usr/share/mediawiki/api.php(90): ApiMain->execute()\n#8 /usr/share/mediawiki/api.php(45): wfApiMain()\n#9 {main}"
    }
}
Cindy.cicalese (talkcontribs)

It would be helpful to know what versions of MediaWiki and extensions you are using as well as what your configuration looks like.

From the exceptions, it looks like your configuration array for AuthManager needs a label element in the array for one of the fields, and that is missing.

That being said, I don't believe that the software is designed to work for your use case: using the API to login and getting back cookies that can be used for SSO. @Tgr (WMF), do you have any thoughts on this?

Uckelman (talkcontribs)

I have installed: MediaWiki 1.35.2, MediaFunctions 1.4.0, ParserFunctions 1.6.0, UserFunctions 2.7.0, Moderation 1.5.34, PluggableAuth 5.7, LDAPProvider 1.0.5, LDAPAuthentication2 1.0.2.

Here is a paste of my LocalSettings.php, with passwords and keys redacted.

We've been using the old LDAPAuthentication plugin to login and pass cookies back to our own SSO setup since 2007, and doing a corresponding thing with Bugzilla and phpBB. Designed to work that way or not, it's worked for 14 years. That said, I'm not wedded to doing it this particular way, so if you have an alternative suggestion I'd be grateful to have it. I looked around for one at the start of this upgrade project and turned up nothing better.

Osnard (talkcontribs)

Can you please give more details on your usecase?

As far as I understood you have some SSO application that will use the APIs of MediaWiki/Bugzilla/phpBB to authenticate and then pass the session cookies back to the client. Apparently the user enters LDAP username/password into the SSO app and this app forwards those to MediaWiki/Bugzilla/phpBB/... and triggers their auth-modules.

Is this SSO app homegrown or some third-party tool?

Maybe using some open standard like SAML or OpenIDConnect would be possible for you?

Uckelman (talkcontribs)

"Apparently the user enters LDAP username/password into the SSO app and this app forwards those to MediaWiki/Bugzilla/phpBB/... and triggers their auth-modules." ----> Yes, that's exactly what we're doing.


The SSO app consists of a few hundred lines of PHP I wrote to display the login page, log in to each of the component parts of the site, collect the cookies, send them back to the user and redirect back to the page the user came from. The SSO app makes an HTTP request to the login facility of each of phpBB, Bugzilla, and MediaWiki, and as they are each able to do LDAP authentication, the user gets logged in and cookies are sent back. (Yes, I realize this means that each component queries LDAP itself, but it was simpler to let each of the three components do whatever they were going to do for logging in and just collect the cookies to send back.)

Tgr (WMF) (talkcontribs)

@Uckelman you are correct that bot passwords can only be used for the API and are not a replacement for web login. clientlogin is intended for providing a login-page-equivalent interactive experience (and is in general hard to use well, as you need to handle everything that can happen on a login page - forced password change, 2FA, captcha etc).

The error sounds like you are using some AuthenticationReuqest which does not return a label field from getFieldInfo(). label and help are required fields and both need to be Message objects.

Osnard (talkcontribs)

The error sounds like you are using some AuthenticationReuqest which does not return a label field from getFieldInfo(). label and help are required fields and both need to be Message objects.

The "AuthenticationRequest" is th one of Extension:PluggableAuth. Maybe we could add the missing information.


@Uckelman I still recommend to switch to a standard SSO solution like SAML. There are some well maintained tools (e.g. SimpleSAMLphp) out there that could be set up to do exactly what you need. This would probably be more sustainable than a homegrown solution.

Uckelman (talkcontribs)

The problem I'm seeing with SAML is not on the MediaWiki side, but with the other two components with which I need to integrate---I don't find much about SAML integration with Bugzilla or phpBB, so by switching to SAML I'd be going from 2 of 3 components working to 1 of 3. :(

Tgr (WMF) (talkcontribs)

@Osnard the extension looks fine; maybe a problem with $wgPluggableAuth_ExtraLoginFields?

Osnard (talkcontribs)
Tgr (WMF) (talkcontribs)

The problem is with lines 41-42. Hidden fields still need label and help, for the API self-documentation.

Osnard (talkcontribs)
Uckelman (talkcontribs)

@Osnard Thank you very much! I'll give the patch a try this evening.

Uckelman (talkcontribs)

@Osnard Your patch lets me get results for /wiki/api.php?action=query&meta=authmanagerinfo&amirequestsfor=login, so that's progress.

Uckelman (talkcontribs)

After the patch, I'm still getting the error message from clientlogin I started with, however.

Tgr (WMF) (talkcontribs)

The original error means none of the authentication providers handled the request (e.g. you sent a username and password but none of the providers are password-based).

A common reason is that the password was incorrect and none of the providers were configured to reject incorrect password (this makes sense if you have multiple password-based providers, like user DB and LDAP, and you want to try the username + password combination for each). See the authoritative constructor parameter of AbstractPasswordPrimaryAuthenticationProvider.

Uckelman (talkcontribs)

I'm nearly certain that the password I'm using is correct, as:

(1) I'm not typing it---my browser is filling it in from my password store.

(2) Before my SSO system calls clientlogin, the SSO system has already authenticated successfully with LDAP using the same password. I've verified that putting in a password I know is wrong fails at that point, and I can see in the slapd log that authenticating with LDAP has succeeded when I use the password supplied by my password store.

(3) When I log in manually to MW in my browser, selecting the same username and letting my browser fill in the password from the password store, logging in succeeds, and I can see MW querying LDAP in the slapd log---which looks different from the logging that happens when my SSO system queries LDAP.

Based on this, I can say fairly confidently that MW is not querying LDAP at all when my SSO script calls clientlogin, because if it were, I would see two queries to LDAP in the log instead of only one.

Uckelman (talkcontribs)

For clarity: The problem seems to be that clientlogin doesn't attempt to authenticate with my LDAP server.

Tgr (WMF) (talkcontribs)

Maybe some other authentication detail is missing that's a precondition of the LDAP auth provider recognizing the request as an LDAP login, e.g. the domain is missing or incorrect?

In general, the error you mentioned happens when all the primary authentication providers return an ABSTAIN from their beginPrimaryAuthentication() method. So you should check what's happening in that method and why it returns ABSTAIN instead of PASS/FAIL, although I imagine for PluggableAuth plugins the PluggableAuth framework will handle beginPrimaryAuthentication() and proxy it to some different method on the plugin - I'm unfamiliar with the details of that.

Uckelman (talkcontribs)

PluggableAuthPrimaryAuthenticationProvider.beginPrimaryAuthentication() is indeed returning ABSTAIN, from the lines at its top:

   $request = ButtonAuthenticationRequest::getRequestByName( $reqs,
     'pluggableauthlogin' );
   if ( !$request ) {
     return AuthenticationResponse::newAbstain();
   }


Osnard (talkcontribs)
Tgr (WMF) (talkcontribs)

So apparently PluggableAuth creates its own submit button instead of relying on the form's default button (I imagine this helps its coexistence with other authentication extensions as it makes it easy to decide whether a login attempt is intended for PluggableAuth or something else), and you need to simulate that in action=clientlogin by adding something like pluggableauthlogin=1 to the request.

Uckelman (talkcontribs)

I've filed a bug report, with a minimal Python script to demonstrate the problem.


Oh, wow, when I added both pluggableauthlogin=1 and domain=LDAP to the POST just now, I got a different result:

{'clientlogin': {'status': 'REDIRECT', 'redirecttarget': 'https://www.test.vassalengine.org/wiki/Special:PluggableAuthLogin', 'requests': [{'id': 'PluggableAuthContinueAuthenticationRequest', 'metadata': {}, 'required': 'required', 'provider': 'PluggableAuthContinueAuthenticationRequest', 'account': 'PluggableAuthContinueAuthenticationRequest', 'fields': {}}]}}


I thought I didn't need the domain parameter when I had a default domain set for the LDAP plugin already.

Uckelman (talkcontribs)

Looks like my next step is to make one more request with logincontinue set? I'll try that later today.

Cindy.cicalese (talkcontribs)

Just clarifying: PluggableAuth is behaving as expected, but it would definitely be helpful to document the need for pluggableauthlogin=1 when usingaction=clientlogin on the extension page. @Tgr (WMF) agreed? Of course, this is pending making sure that the rest of the flow works as expected.

Tgr (WMF) (talkcontribs)

I think so, yes.

Uckelman (talkcontribs)

It looks like I can only call logincontinue after the redirect has happend, but I don't see how I can wait for the redirect from my SSO script. Is there a way to continue the process whereby I get a reply directly instead?

Tgr (WMF) (talkcontribs)

Usually people use AJAX or a popup window (or an URL parameter to store state, but the SSO server has to cooperate for that). In a bind, I'd try using localStorage.

Trying to continue before the redirect makes no sense as presumably the redirect triggers some kind of central authentication step that needs to be verified during logincontinue.

Reply to "{"clientlogin":{"status":"FAIL","message":"The supplied credentials could not be authenticated.","messagecode":"authmanager-authn-no-primary"}}"