Quantcast
Viewing all articles
Browse latest Browse all 295783

Remove dependency of current_user on request and authentication manager

This issue is part of #2371629: [meta] Finalize Session and User Authentication API and #2047951: [META] Remove calls to deprecated global $user and $GLOBALS['user']

Problem/Motivation

The coupling of the 'current_user' service to AuthenticationManager creates a circular dependency that makes it difficult to implement alternative authentication schemes like basic_auth (see #2283637: Session for an authenticated user can only be set by Cookie AuthenticationProvider). The current_user service originally was a synthetic service that caused problems. #2180109: Change the current_user service to a proxy fixed these problems by
a) introducing a transparent proxy around the actual user object in order to remove the requirement to declare it synthetic and
b)introducing on-demand authentication (i.e. user authentication is triggered as soon as a method is called on the current_user object).

However, in order to solve the problems a) is sufficient. b), however, introduces the possibility of user authentication with different authentication methods at multiple points in the request/response cycle e.g. when the container is rebuilt during tests or when enabling/disabling modules. If there are credentials for multiple authentication methods on one request (e.g. a developer logged into a site, testing some requests with token authentication), the behavior of the authentication system is hard to predict (see #104).

Authentication must only be performed once during the request / response cycle. User authentication requires checking the credentials sent along with the initial HTTP request based on a pre-selected authentication method.

The current system allows for a mix of multiple authentication methods. Because not all of them are equally secure, the system needs to support the restriction of authentication methods to only a subset of the site. This is especially true for HTTP basic authentication or URL token based authentication which are commonly used for machine-to-machine communication.

On a 403 (access denied), if there are no credentials on the request, some authentication methods (e.g. basic auth) require that a challenge is sent to the client. For obvious reasons this functionality also needs to be restricted to those routes where such providers are active.

Currently this dilemma is resolved by resetting authentication from within AuthenticationEnhancer if there is a mismatch between the allowed authentication methods and the chosen one. In order to minimize the opportunity for security problems, it would be better to simply bail out and deny access in this case.

Proposed resolution

  • Remove the on-demand authentication of the current user in AccountProxy::setAccount() and implement authentication in an EventSubscriber that runs before language processing, routing and any other consumer of the current_user service. This provides a single point of entry for authentication which is easier to audit and control. This effectively removes the dependency of the current_user service on the authentication manager and the request object.
  • Remove the AuthenticationEnhancer and replace it with an additional request listener on the AuthenticationSubscriber. The new listener runs after routing and filters the selected authentication provider according to the list of allowed providers specified in the _auth option of the current route. Throws AccessDeniedHttpException exception if it detects a mismatch.
  • Make sure that all implementers of AuthenticationProviderInterface respect the liskov substitution principle, i.e. AuthenticationManager should not be a special flower, neither should BasicAuth or the Cookie provider. Also ensure that AuthenticationSubscriber accepts any AuthenticationProviderInterface.

Remaining tasks

Reviews and commit.

User interface changes

None

API changes

  1. AuthenticationManagerInterface is completely removed
  2. AuthenticationProviderInterface methods removed:
    • cleanup() (dead code)
    • handleException() (moved to new <code>AuthenticationProviderChallengeInterface)
  3. AuthenticationEnhancer replaced by implementors of AuthenticationProviderFilterInterface, called from AuthenticationSubscriber

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue priorityCritical
Prioritized changesThe main goal of this issue is security and reducing brittleness.
DisruptionMildly disruptive for core/contributed/custom modules

Viewing all articles
Browse latest Browse all 295783