<commit_before><?php
namespace TYPO3\Flow\Security\Authentication;

/*                                                                        *
 * This script belongs to the TYPO3 Flow framework.                       *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU Lesser General Public License, either version 3   *
 * of the License, or (at your option) any later version.                 *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Log\SecurityLoggerInterface;
use TYPO3\Flow\Security\Account;
use TYPO3\Flow\Security\Authentication\Token\SessionlessTokenInterface;
use TYPO3\Flow\Security\Context;
use TYPO3\Flow\Security\Exception\NoTokensAuthenticatedException;
use TYPO3\Flow\Security\Exception\AuthenticationRequiredException;
use TYPO3\Flow\Security\Exception;
use TYPO3\Flow\Security\RequestPatternResolver;
use TYPO3\Flow\Session\SessionInterface;

/**
 * The default authentication manager, which relies on Authentication Providers
 * to authenticate the tokens stored in the security context.
 *
 * @Flow\Scope("singleton")
 */
class AuthenticationProviderManager implements AuthenticationManagerInterface {

	/**
	 * @Flow\Inject
	 * @var SecurityLoggerInterface
	 */
	protected $securityLogger;

	/**
	 * @var SessionInterface
	 * @Flow\Inject
	 */
	protected $session;

	/**
	 * The provider resolver
	 *
	 * @var AuthenticationProviderResolver
	 */
	protected $providerResolver;

	/**
	 * The security context of the current request
	 *
	 * @var Context
	 */
	protected $securityContext;

	/**
	 * The request pattern resolver
	 *
	 * @var RequestPatternResolver
	 */
	protected $requestPatternResolver;

	/**
	 * Array of \TYPO3\Flow\Security\Authentication\AuthenticationProviderInterface objects
	 *
	 * @var array
	 */
	protected $providers = array();

	/**
	 * Array of \TYPO3\Flow\Security\Authentication\TokenInterface objects
	 *
	 * @var array
	 */
	protected $tokens = array();

	/**
	 * @var boolean
	 */
	protected $isAuthenticated = NULL;

	/**
	 * @param AuthenticationProviderResolver $providerResolver The provider resolver
	 * @param RequestPatternResolver $requestPatternResolver The request pattern resolver
	 */
	public function __construct(AuthenticationProviderResolver $providerResolver, RequestPatternResolver $requestPatternResolver) {
		$this->providerResolver = $providerResolver;
		$this->requestPatternResolver = $requestPatternResolver;
	}

	/**
	 * Inject the settings and does a fresh build of tokens based on the injected settings
	 *
	 * @param array $settings The settings
	 * @return void
	 */
	public function injectSettings(array $settings) {
		if (!isset($settings['security']['authentication']['providers']) || !is_array($settings['security']['authentication']['providers'])) {
			return;
		}

		$this->buildProvidersAndTokensFromConfiguration($settings['security']['authentication']['providers']);
	}

	/**
	 * Sets the security context
	 *
	 * @param Context $securityContext The security context of the current request
	 * @return void
	 */
	public function setSecurityContext(Context $securityContext) {
		$this->securityContext = $securityContext;
	}

	/**
	 * Returns the security context
	 *
	 * @return Context $securityContext The security context of the current request
	 */
	public function getSecurityContext() {
		return $this->securityContext;
	}

	/**
	 * Returns clean tokens this manager is responsible for.
	 * Note: The order of the tokens in the array is important, as the tokens will be authenticated in the given order.
	 *
	 * @return array Array of \TYPO3\Flow\Security\Authentication\TokenInterface An array of tokens this manager is responsible for
	 */
	public function getTokens() {
		return $this->tokens;
	}

	/**
	 * Tries to authenticate the tokens in the security context (in the given order)
	 * with the available authentication providers, if needed.
	 * If the authentication strategy is set to "allTokens", all tokens have to be authenticated.
	 * If the strategy is set to "oneToken", only one token needs to be authenticated, but the
	 * authentication will stop after the first authenticated token. The strategy
	 * "atLeastOne" will try to authenticate at least one and as many tokens as possible.
	 *
	 * @return void
	 * @throws \TYPO3\Flow\Security\Exception
	 * @throws \TYPO3\Flow\Security\Exception\AuthenticationRequiredException
	 */
	public function authenticate() {
		$this->isAuthenticated = FALSE;
		$anyTokenAuthenticated = FALSE;

		if ($this->securityContext === NULL) {
			throw new Exception('Cannot authenticate because no security context has been set.', 1232978667);
		}

		$tokens = $this->securityContext->getAuthenticationTokens();
		if (count($tokens) === 0) {
			throw new NoTokensAuthenticatedException('The security context contained no tokens which could be authenticated.', 1258721059);
		}

		/** @var $token TokenInterface */
		foreach ($tokens as $token) {
			/** @var $provider AuthenticationProviderInterface */
			foreach ($this->providers as $provider) {
				if ($provider->canAuthenticate($token) && $token->getAuthenticationStatus() === TokenInterface::AUTHENTICATION_NEEDED) {
					$provider->authenticate($token);
					if ($token->isAuthenticated()) {
						$this->emitAuthenticatedToken($token);
					}
					break;
				}
			}
			if ($token->isAuthenticated()) {
				if (!$token instanceof SessionlessTokenInterface) {
					if (!$this->session->isStarted()) {
						$this->session->start();
					}
					$account = $token->getAccount();
					if ($account !== NULL) {
						$this->session->addTag('TYPO3-Flow-Security-Account-' . md5($account->getAccountIdentifier()));
					}
				}
				if ($this->securityContext->getAuthenticationStrategy() === Context::AUTHENTICATE_ONE_TOKEN) {
					$this->isAuthenticated = TRUE;
					$this->securityContext->setContextHashComponent('TYPO3.Flow:Roles', $this->securityContext->getRolesHash());
					return;
				}
				$anyTokenAuthenticated = TRUE;
			} else {
				if ($this->securityContext->getAuthenticationStrategy() === Context::AUTHENTICATE_ALL_TOKENS) {
					throw new AuthenticationRequiredException('Could not authenticate all tokens, but authenticationStrategy was set to "all".', 1222203912);
				}
			}
		}

		if (!$anyTokenAuthenticated && $this->securityContext->getAuthenticationStrategy() !== Context::AUTHENTICATE_ANY_TOKEN) {
			throw new NoTokensAuthenticatedException('Could not authenticate any token. Might be missing or wrong credentials or no authentication provider matched.', 1222204027);<commit_msg>[BUGFIX] Account tagging causes Access Denied<commit_after><?php
namespace TYPO3\Flow\Security\Authentication;

/*                                                                        *
 * This script belongs to the TYPO3 Flow framework.                       *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU Lesser General Public License, either version 3   *
 * of the License, or (at your option) any later version.                 *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Log\SecurityLoggerInterface;
use TYPO3\Flow\Security\Account;
use TYPO3\Flow\Security\Authentication\Token\SessionlessTokenInterface;
use TYPO3\Flow\Security\Context;
use TYPO3\Flow\Security\Exception\NoTokensAuthenticatedException;
use TYPO3\Flow\Security\Exception\AuthenticationRequiredException;
use TYPO3\Flow\Security\Exception;
use TYPO3\Flow\Security\RequestPatternResolver;
use TYPO3\Flow\Session\SessionInterface;

/**
 * The default authentication manager, which relies on Authentication Providers
 * to authenticate the tokens stored in the security context.
 *
 * @Flow\Scope("singleton")
 */
class AuthenticationProviderManager implements AuthenticationManagerInterface {

	/**
	 * @Flow\Inject
	 * @var SecurityLoggerInterface
	 */
	protected $securityLogger;

	/**
	 * @var SessionInterface
	 * @Flow\Inject
	 */
	protected $session;

	/**
	 * The provider resolver
	 *
	 * @var AuthenticationProviderResolver
	 */
	protected $providerResolver;

	/**
	 * The security context of the current request
	 *
	 * @var Context
	 */
	protected $securityContext;

	/**
	 * The request pattern resolver
	 *
	 * @var RequestPatternResolver
	 */
	protected $requestPatternResolver;

	/**
	 * Array of \TYPO3\Flow\Security\Authentication\AuthenticationProviderInterface objects
	 *
	 * @var array
	 */
	protected $providers = array();

	/**
	 * Array of \TYPO3\Flow\Security\Authentication\TokenInterface objects
	 *
	 * @var array
	 */
	protected $tokens = array();

	/**
	 * @var boolean
	 */
	protected $isAuthenticated = NULL;

	/**
	 * @param AuthenticationProviderResolver $providerResolver The provider resolver
	 * @param RequestPatternResolver $requestPatternResolver The request pattern resolver
	 */
	public function __construct(AuthenticationProviderResolver $providerResolver, RequestPatternResolver $requestPatternResolver) {
		$this->providerResolver = $providerResolver;
		$this->requestPatternResolver = $requestPatternResolver;
	}

	/**
	 * Inject the settings and does a fresh build of tokens based on the injected settings
	 *
	 * @param array $settings The settings
	 * @return void
	 */
	public function injectSettings(array $settings) {
		if (!isset($settings['security']['authentication']['providers']) || !is_array($settings['security']['authentication']['providers'])) {
			return;
		}

		$this->buildProvidersAndTokensFromConfiguration($settings['security']['authentication']['providers']);
	}

	/**
	 * Sets the security context
	 *
	 * @param Context $securityContext The security context of the current request
	 * @return void
	 */
	public function setSecurityContext(Context $securityContext) {
		$this->securityContext = $securityContext;
	}

	/**
	 * Returns the security context
	 *
	 * @return Context $securityContext The security context of the current request
	 */
	public function getSecurityContext() {
		return $this->securityContext;
	}

	/**
	 * Returns clean tokens this manager is responsible for.
	 * Note: The order of the tokens in the array is important, as the tokens will be authenticated in the given order.
	 *
	 * @return array Array of \TYPO3\Flow\Security\Authentication\TokenInterface An array of tokens this manager is responsible for
	 */
	public function getTokens() {
		return $this->tokens;
	}

	/**
	 * Tries to authenticate the tokens in the security context (in the given order)
	 * with the available authentication providers, if needed.
	 * If the authentication strategy is set to "allTokens", all tokens have to be authenticated.
	 * If the strategy is set to "oneToken", only one token needs to be authenticated, but the
	 * authentication will stop after the first authenticated token. The strategy
	 * "atLeastOne" will try to authenticate at least one and as many tokens as possible.
	 *
	 * @return void
	 * @throws \TYPO3\Flow\Security\Exception
	 * @throws \TYPO3\Flow\Security\Exception\AuthenticationRequiredException
	 */
	public function authenticate() {
		$this->isAuthenticated = FALSE;
		$anyTokenAuthenticated = FALSE;

		if ($this->securityContext === NULL) {
			throw new Exception('Cannot authenticate because no security context has been set.', 1232978667);
		}

		$tokens = $this->securityContext->getAuthenticationTokens();
		if (count($tokens) === 0) {
			throw new NoTokensAuthenticatedException('The security context contained no tokens which could be authenticated.', 1258721059);
		}

		/** @var $token TokenInterface */
		foreach ($tokens as $token) {
			/** @var $provider AuthenticationProviderInterface */
			foreach ($this->providers as $provider) {
				if ($provider->canAuthenticate($token) && $token->getAuthenticationStatus() === TokenInterface::AUTHENTICATION_NEEDED) {
					$provider->authenticate($token);
					if ($token->isAuthenticated()) {
						$this->emitAuthenticatedToken($token);
					}
					break;
				}
			}
			if ($token->isAuthenticated()) {
				if (!$token instanceof SessionlessTokenInterface) {
					if (!$this->session->isStarted()) {
						$this->session->start();
					}
					$account = $token->getAccount();
					if ($account !== NULL) {
						$this->securityContext->withoutAuthorizationChecks(function() use ($account) {
							$this->session->addTag('TYPO3-Flow-Security-Account-' . md5($account->getAccountIdentifier()));
						});
					}
				}
				if ($this->securityContext->getAuthenticationStrategy() === Context::AUTHENTICATE_ONE_TOKEN) {
					$this->isAuthenticated = TRUE;
					$this->securityContext->setContextHashComponent('TYPO3.Flow:Roles', $this->securityContext->getRolesHash());
					return;
				}
				$anyTokenAuthenticated = TRUE;
			} else {
				if ($this->securityContext->getAuthenticationStrategy() === Context::AUTHENTICATE_ALL_TOKENS) {
					throw new AuthenticationRequiredException('Could not authenticate all tokens, but authenticationStrategy was set to "all".', 1222203912);
				}
			}
		}

		if (!$anyTokenAuthenticated && $this->securityContext->getAuthenticationStrategy() !== Context::AUTHENTICATE_ANY_TOKEN) {
			throw new NoTokensAuthenticatedException('Could not authenticate any token. Might be missing or wrong credentials or no authentication provider matched.', 1222204027);
{'fraction_non_alphanumeric': 0.1055098802827059, 'fraction_numerical': 0.009086975335352661, 'mean_word_length': 3.4050190597204573, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6082301', 'n_tokens_mistral': 4001, 'n_tokens_neox': 3501, 'n_words': 1025}