Use same credential provider for two different tokens

Hi,

I’ve sort of hijacked this GitHub issue: https://github.com/neos/flow-development-collection/issues/1944#issuecomment-613917896 asking about something that’s not directly related but still important.
Currently the PersistentUsernamePasswordProvider can handle HTTP Basic and the regular stuff via POST parameters sent from a login form. That’s fine in general but you can always have only one or the other.
Another problem is that if you use a WebRedirect that is also kicking in for requests that using HTTP Basic Authentication which is wrong since it should return Status 401 with Authorization required.

The use case I have for this (and have solved it via some hacky custom-implemented providers/tokens/EntryPoints) is the following:
I have developed an app that has a web interface where users log in regularly (https://thw-app.de). The app in general allows branches of THW to sign up (private beta currently) and manage their trucks, units, members/users, invite people to mandatory or non-mandatory events. So there’s a lot of different data in it.
I’ve now added CardDAV and CalDAV support using SabreDav and wanted to give people a way of just entering some URL of the application on their phone and use their regular username and password to log in so they don’t need additional credentials. That way they get all their data in their addressbook and calendar that they also see in the app.
IMO that’s a very valid use case to use the same credentials in two different ways but as far as I know there’s currently no way of doing that in Flow without implementing these things as custom classes.

Would be happy to discuss this and also like to know if there are ideas on how to solve it.

Thanks,
David

Hi David,

thanks a lot for starting this thread and explaining your use case!
It’s absolutely valid of course and I’m with you: We should definitely support it “out of the box”

I’m not familiar with the *DAV protocols but IIRC they usually do authentication via BASIC or DIGEST AUTH, right?
In any case, if the credentials end up as username/password in the request somehow, it should be possible to re-use the PersistedUsernamePasswordProvider for both tokens IMO.

Currently only one token per provider is evaluated (see flow-development-collection/Neos.Flow/Classes/Security/Authentication/TokenAndProviderFactory.php at 8.2 · neos/flow-development-collection · GitHub) no matter what the configured authenticationStrategy is…

We could extend that, but we would need to be able to define custom entry points and request patterns per token.

I just tried out a 1-line change that would be backwards compatible and provide the same functionality basically.
The idea would be to be able to override the provider name:

Neos:
  Flow:
    security:
      authentication:
        providers:
          'Acme.SomePackage:Default':
            requestPatterns:
              'Acme.SomePackage:SomePattern':
                pattern: 'SomePattern'

            provider: PersistedUsernamePasswordProvider
            token: UsernamePassword
            entryPoint: WebRedirect
            entryPointOptions:
              routeValues:
                '@package': Acme.SomePackage
                '@controller': Authentication
                '@action': login

          'Acme.SomePackage:Default.HttpBasic':
            name: 'Acme.SomePackage:Default'

            requestPatterns:
              'Acme.SomePackage:SomeOtherPattern':
                pattern: 'SomeOtherPattern'

            provider: PersistedUsernamePasswordProvider
            token: UsernamePasswordHttpBasic
            entryPoint: HttpBasic

(the line name: 'Acme.SomePackage:Default' is the relevant one)

Alternatively I could imagine a provider option that is evaluated in the findActiveByAccountIdentifierAndAuthenticationProviderName() call of the PersistedUsernamePasswordProvider so that we can lookup users for a different provider:

Neos:
  Flow:
    security:
      authentication:
        providers:
          'Acme.SomePackage:Default':
            # ...

          'Acme.SomePackage:Default.HttpBasic':
            provider: PersistedUsernamePasswordProvider
            providerOptions:
              lookupName: 'Acme.SomePackage:Default'

It’s also a backwards compatible 1-line-change and its probably even cleaner as it doesn’t mess with the provider name. But to make use of it a provider needs to evaluate that option.

Thanks Bastian!
I think for the sake of clarity the second option would be better even if it requires the provider to support it.
Just a thought: theoretically it should be possible to change the name in the constructor of the AbstractProvider I guess. Means if there’s a lookupName in the providerOptions use that instead of the actual name.
Not sure if that would have other side effects but it would be a way to have the cleaner option in Settings.yaml and it would enable support for that in all providers that extend the AbstractProvider, right?

That’s basically what my first solution does (only it sets a different name from the “outside”, i.e. when creating the instance).
But I think it’s actually a good idea to keep the provider names separate because you don’t want to have something like “failed for provider XYZ” in your log files if it was actually a different provider

@david.sporer https://github.com/neos/flow-development-collection/pull/1993 this could work.
If you open a ticket I’ll finish the PR :slight_smile:

Awesome! I’ll do that tomorrow, I’m on the road for THW today :wink:

Good morning @bwaidelich: here it is: https://github.com/neos/flow-development-collection/issues/1996
Let me know if this issue requires more info.