summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes M. Schmitt <schmittjoh@gmail.com>2011-01-26 21:34:11 +0100
committerFabien Potencier <fabien.potencier@gmail.com>2011-01-26 22:23:20 +0100
commitbebc09870cb0a7720e2c6a8c5c74585e69e8bb24 (patch)
tree0c399647cdbe504be405017e7cc04c70c53482f2
parentc85f3d708d2c9b00d73ca1234ccfaf50336d94b1 (diff)
downloadsymfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.zip
symfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.tar.gz
symfony-security-bebc09870cb0a7720e2c6a8c5c74585e69e8bb24.tar.bz2
namespace changes
Symfony\Component\Security -> Symfony\Component\Security\Core Symfony\Component\Security\Acl remains unchanged Symfony\Component\HttpKernel\Security -> Symfony\Component\Security\Http
-rw-r--r--Acl/Domain/RoleSecurityIdentity.php2
-rw-r--r--Acl/Domain/SecurityIdentityRetrievalStrategy.php12
-rw-r--r--Acl/Domain/UserSecurityIdentity.php4
-rw-r--r--Acl/Model/SecurityIdentityRetrievalStrategyInterface.php2
-rw-r--r--Acl/Voter/AclVoter.php6
-rw-r--r--Core/Authentication/AuthenticationManagerInterface.php (renamed from Authentication/AuthenticationManagerInterface.php)6
-rw-r--r--Core/Authentication/AuthenticationProviderManager.php (renamed from Authentication/AuthenticationProviderManager.php)12
-rw-r--r--Core/Authentication/AuthenticationTrustResolver.php (renamed from Authentication/AuthenticationTrustResolver.php)4
-rw-r--r--Core/Authentication/AuthenticationTrustResolverInterface.php (renamed from Authentication/AuthenticationTrustResolverInterface.php)4
-rw-r--r--Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php (renamed from Authentication/EntryPoint/AuthenticationEntryPointInterface.php)4
-rw-r--r--Core/Authentication/Provider/AnonymousAuthenticationProvider.php (renamed from Authentication/Provider/AnonymousAuthenticationProvider.php)8
-rw-r--r--Core/Authentication/Provider/AuthenticationProviderInterface.php (renamed from Authentication/Provider/AuthenticationProviderInterface.php)6
-rw-r--r--Core/Authentication/Provider/DaoAuthenticationProvider.php (renamed from Authentication/Provider/DaoAuthenticationProvider.php)20
-rw-r--r--Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php (renamed from Authentication/Provider/PreAuthenticatedAuthenticationProvider.php)14
-rw-r--r--Core/Authentication/Provider/RememberMeAuthenticationProvider.php (renamed from Authentication/Provider/RememberMeAuthenticationProvider.php)12
-rw-r--r--Core/Authentication/Provider/UserAuthenticationProvider.php (renamed from Authentication/Provider/UserAuthenticationProvider.php)20
-rw-r--r--Core/Authentication/RememberMe/InMemoryTokenProvider.php (renamed from Authentication/RememberMe/InMemoryTokenProvider.php)4
-rw-r--r--Core/Authentication/RememberMe/PersistentToken.php (renamed from Authentication/RememberMe/PersistentToken.php)2
-rw-r--r--Core/Authentication/RememberMe/PersistentTokenInterface.php (renamed from Authentication/RememberMe/PersistentTokenInterface.php)2
-rw-r--r--Core/Authentication/RememberMe/TokenProviderInterface.php (renamed from Authentication/RememberMe/TokenProviderInterface.php)2
-rw-r--r--Core/Authentication/Token/AnonymousToken.php (renamed from Authentication/Token/AnonymousToken.php)2
-rw-r--r--Core/Authentication/Token/PreAuthenticatedToken.php (renamed from Authentication/Token/PreAuthenticatedToken.php)2
-rw-r--r--Core/Authentication/Token/RememberMeToken.php (renamed from Authentication/Token/RememberMeToken.php)6
-rw-r--r--Core/Authentication/Token/Token.php (renamed from Authentication/Token/Token.php)8
-rw-r--r--Core/Authentication/Token/TokenInterface.php (renamed from Authentication/Token/TokenInterface.php)4
-rw-r--r--Core/Authentication/Token/UsernamePasswordToken.php (renamed from Authentication/Token/UsernamePasswordToken.php)2
-rw-r--r--Core/Authorization/AccessDecisionManager.php (renamed from Authorization/AccessDecisionManager.php)6
-rw-r--r--Core/Authorization/AccessDecisionManagerInterface.php (renamed from Authorization/AccessDecisionManagerInterface.php)4
-rw-r--r--Core/Authorization/Voter/AuthenticatedVoter.php (renamed from Authorization/Voter/AuthenticatedVoter.php)6
-rw-r--r--Core/Authorization/Voter/RoleHierarchyVoter.php (renamed from Authorization/Voter/RoleHierarchyVoter.php)6
-rw-r--r--Core/Authorization/Voter/RoleVoter.php (renamed from Authorization/Voter/RoleVoter.php)4
-rw-r--r--Core/Authorization/Voter/VoterInterface.php (renamed from Authorization/Voter/VoterInterface.php)4
-rw-r--r--Core/Encoder/BasePasswordEncoder.php (renamed from Encoder/BasePasswordEncoder.php)2
-rw-r--r--Core/Encoder/EncoderFactory.php (renamed from Encoder/EncoderFactory.php)4
-rw-r--r--Core/Encoder/EncoderFactoryInterface.php (renamed from Encoder/EncoderFactoryInterface.php)4
-rw-r--r--Core/Encoder/MessageDigestPasswordEncoder.php (renamed from Encoder/MessageDigestPasswordEncoder.php)2
-rw-r--r--Core/Encoder/PasswordEncoderInterface.php (renamed from Encoder/PasswordEncoderInterface.php)2
-rw-r--r--Core/Encoder/PlaintextPasswordEncoder.php (renamed from Encoder/PlaintextPasswordEncoder.php)2
-rw-r--r--Core/Exception/AccessDeniedException.php (renamed from Exception/AccessDeniedException.php)2
-rw-r--r--Core/Exception/AccountExpiredException.php (renamed from Exception/AccountExpiredException.php)2
-rw-r--r--Core/Exception/AccountStatusException.php (renamed from Exception/AccountStatusException.php)2
-rw-r--r--Core/Exception/AuthenticationCredentialsNotFoundException.php (renamed from Exception/AuthenticationCredentialsNotFoundException.php)2
-rw-r--r--Core/Exception/AuthenticationException.php (renamed from Exception/AuthenticationException.php)2
-rw-r--r--Core/Exception/AuthenticationServiceException.php (renamed from Exception/AuthenticationServiceException.php)2
-rw-r--r--Core/Exception/BadCredentialsException.php (renamed from Exception/BadCredentialsException.php)2
-rw-r--r--Core/Exception/CookieTheftException.php (renamed from Exception/CookieTheftException.php)2
-rw-r--r--Core/Exception/CredentialsExpiredException.php (renamed from Exception/CredentialsExpiredException.php)2
-rw-r--r--Core/Exception/DisabledException.php (renamed from Exception/DisabledException.php)2
-rw-r--r--Core/Exception/InsufficientAuthenticationException.php (renamed from Exception/InsufficientAuthenticationException.php)2
-rw-r--r--Core/Exception/LockedException.php (renamed from Exception/LockedException.php)2
-rw-r--r--Core/Exception/NonceExpiredException.php (renamed from Exception/NonceExpiredException.php)4
-rw-r--r--Core/Exception/ProviderNotFoundException.php (renamed from Exception/ProviderNotFoundException.php)2
-rw-r--r--Core/Exception/TokenNotFoundException.php (renamed from Exception/TokenNotFoundException.php)2
-rw-r--r--Core/Exception/UnsupportedAccountException.php (renamed from Exception/UnsupportedAccountException.php)2
-rw-r--r--Core/Exception/UsernameNotFoundException.php (renamed from Exception/UsernameNotFoundException.php)2
-rw-r--r--Core/Role/Role.php (renamed from Role/Role.php)2
-rw-r--r--Core/Role/RoleHierarchy.php (renamed from Role/RoleHierarchy.php)2
-rw-r--r--Core/Role/RoleHierarchyInterface.php (renamed from Role/RoleHierarchyInterface.php)2
-rw-r--r--Core/Role/RoleInterface.php (renamed from Role/RoleInterface.php)2
-rw-r--r--Core/Role/SwitchUserRole.php (renamed from Role/SwitchUserRole.php)4
-rw-r--r--Core/SecurityContext.php (renamed from SecurityContext.php)8
-rw-r--r--Core/User/AccountChecker.php (renamed from User/AccountChecker.php)10
-rw-r--r--Core/User/AccountCheckerInterface.php (renamed from User/AccountCheckerInterface.php)2
-rw-r--r--Core/User/AccountInterface.php (renamed from User/AccountInterface.php)2
-rw-r--r--Core/User/AdvancedAccountInterface.php (renamed from User/AdvancedAccountInterface.php)2
-rw-r--r--Core/User/InMemoryUserProvider.php (renamed from User/InMemoryUserProvider.php)8
-rw-r--r--Core/User/User.php (renamed from User/User.php)2
-rw-r--r--Core/User/UserProviderInterface.php (renamed from User/UserProviderInterface.php)2
-rw-r--r--Http/AccessMap.php49
-rw-r--r--Http/Authentication/AuthenticationFailureHandlerInterface.php11
-rw-r--r--Http/Authentication/AuthenticationSuccessHandlerInterface.php12
-rw-r--r--Http/EntryPoint/BasicAuthenticationEntryPoint.php41
-rw-r--r--Http/EntryPoint/DigestAuthenticationEntryPoint.php74
-rw-r--r--Http/EntryPoint/FormAuthenticationEntryPoint.php56
-rw-r--r--Http/EntryPoint/RetryAuthenticationEntryPoint.php60
-rw-r--r--Http/ExceptionTranslation/AccessDeniedHandlerInterface.php27
-rw-r--r--Http/Firewall.php95
-rw-r--r--Http/Firewall/AbstractAuthenticationListener.php285
-rw-r--r--Http/Firewall/AccessListener.php92
-rw-r--r--Http/Firewall/AnonymousAuthenticationListener.php77
-rw-r--r--Http/Firewall/BasicAuthenticationListener.php115
-rw-r--r--Http/Firewall/ChannelListener.php88
-rw-r--r--Http/Firewall/ContextListener.php175
-rw-r--r--Http/Firewall/DigestAuthenticationListener.php239
-rw-r--r--Http/Firewall/ExceptionListener.php170
-rw-r--r--Http/Firewall/ListenerInterface.php42
-rw-r--r--Http/Firewall/LogoutListener.php105
-rw-r--r--Http/Firewall/PreAuthenticatedListener.php116
-rw-r--r--Http/Firewall/RememberMeListener.php148
-rw-r--r--Http/Firewall/SwitchUserListener.php184
-rw-r--r--Http/Firewall/UsernamePasswordFormAuthenticationListener.php64
-rw-r--r--Http/Firewall/X509AuthenticationListener.php46
-rw-r--r--Http/FirewallMap.php43
-rw-r--r--Http/FirewallMapInterface.php28
-rw-r--r--Http/Logout/CookieClearingLogoutHandler.php59
-rw-r--r--Http/Logout/LogoutHandlerInterface.php36
-rw-r--r--Http/Logout/SessionLogoutHandler.php37
-rw-r--r--Http/RememberMe/PersistentTokenBasedRememberMeServices.php165
-rw-r--r--Http/RememberMe/RememberMeServices.php250
-rw-r--r--Http/RememberMe/RememberMeServicesInterface.php66
-rw-r--r--Http/RememberMe/TokenBasedRememberMeServices.php153
-rw-r--r--Http/Session/SessionAuthenticationStrategy.php39
-rw-r--r--Http/Session/SessionAuthenticationStrategyInterface.php11
103 files changed, 3408 insertions, 150 deletions
diff --git a/Acl/Domain/RoleSecurityIdentity.php b/Acl/Domain/RoleSecurityIdentity.php
index 0a55fda..26a1309 100644
--- a/Acl/Domain/RoleSecurityIdentity.php
+++ b/Acl/Domain/RoleSecurityIdentity.php
@@ -12,7 +12,7 @@
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
-use Symfony\Component\Security\Role\Role;
+use Symfony\Component\Security\Core\Role\Role;
/**
* A SecurityIdentity implementation for roles
diff --git a/Acl/Domain/SecurityIdentityRetrievalStrategy.php b/Acl/Domain/SecurityIdentityRetrievalStrategy.php
index d347b97..ae21733 100644
--- a/Acl/Domain/SecurityIdentityRetrievalStrategy.php
+++ b/Acl/Domain/SecurityIdentityRetrievalStrategy.php
@@ -11,14 +11,14 @@
namespace Symfony\Component\Security\Acl\Domain;
-use Symfony\Component\Security\Authentication\Token\AnonymousToken;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
-use Symfony\Component\Security\User\AccountInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
-use Symfony\Component\Security\Authentication\AuthenticationTrustResolver;
-use Symfony\Component\Security\Role\RoleHierarchyInterface;
-use Symfony\Component\Security\Authorization\Voter\AuthenticatedVoter;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
+use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
/**
* Strategy for retrieving security identities
diff --git a/Acl/Domain/UserSecurityIdentity.php b/Acl/Domain/UserSecurityIdentity.php
index 3c30a96..ed94f64 100644
--- a/Acl/Domain/UserSecurityIdentity.php
+++ b/Acl/Domain/UserSecurityIdentity.php
@@ -11,8 +11,8 @@
namespace Symfony\Component\Security\Acl\Domain;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
diff --git a/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php b/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php
index 6761216..d107615 100644
--- a/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php
+++ b/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php
@@ -11,7 +11,7 @@
namespace Symfony\Component\Security\Acl\Model;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Interface for retrieving security identities from tokens
diff --git a/Acl/Voter/AclVoter.php b/Acl/Voter/AclVoter.php
index 7230e35..ee9a758 100644
--- a/Acl/Voter/AclVoter.php
+++ b/Acl/Voter/AclVoter.php
@@ -21,9 +21,9 @@ use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Permission\PermissionMapInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Authorization\Voter\VoterInterface;
-use Symfony\Component\Security\Role\RoleHierarchyInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
* This voter can be used as a base class for implementing your own permissions.
diff --git a/Authentication/AuthenticationManagerInterface.php b/Core/Authentication/AuthenticationManagerInterface.php
index 10625c7..280377a 100644
--- a/Authentication/AuthenticationManagerInterface.php
+++ b/Core/Authentication/AuthenticationManagerInterface.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication;
+namespace Symfony\Component\Security\Core\Authentication;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
/**
* AuthenticationManagerInterface is the interface for authentication managers,
diff --git a/Authentication/AuthenticationProviderManager.php b/Core/Authentication/AuthenticationProviderManager.php
index 35ce996..187a81b 100644
--- a/Authentication/AuthenticationProviderManager.php
+++ b/Core/Authentication/AuthenticationProviderManager.php
@@ -9,13 +9,13 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication;
+namespace Symfony\Component\Security\Core\Authentication;
-use Symfony\Component\Security\Exception\AccountStatusException;
-use Symfony\Component\Security\Exception\AuthenticationException;
-use Symfony\Component\Security\Exception\ProviderNotFoundException;
-use Symfony\Component\Security\Authentication\Provider\AuthenticationProviderInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\AccountStatusException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\ProviderNotFoundException;
+use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AuthenticationProviderManager uses a list of AuthenticationProviderInterface
diff --git a/Authentication/AuthenticationTrustResolver.php b/Core/Authentication/AuthenticationTrustResolver.php
index 94e01eb..95b8cb4 100644
--- a/Authentication/AuthenticationTrustResolver.php
+++ b/Core/Authentication/AuthenticationTrustResolver.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication;
+namespace Symfony\Component\Security\Core\Authentication;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* The default implementation of the authentication trust resolver.
diff --git a/Authentication/AuthenticationTrustResolverInterface.php b/Core/Authentication/AuthenticationTrustResolverInterface.php
index 47d4789..1f29465 100644
--- a/Authentication/AuthenticationTrustResolverInterface.php
+++ b/Core/Authentication/AuthenticationTrustResolverInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication;
+namespace Symfony\Component\Security\Core\Authentication;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Interface for resolving the authentication status of a given token.
diff --git a/Authentication/EntryPoint/AuthenticationEntryPointInterface.php b/Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php
index 004837f..7fd64bf 100644
--- a/Authentication/EntryPoint/AuthenticationEntryPointInterface.php
+++ b/Core/Authentication/EntryPoint/AuthenticationEntryPointInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\EntryPoint;
+namespace Symfony\Component\Security\Core\Authentication\EntryPoint;
-use Symfony\Component\Security\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
/**
diff --git a/Authentication/Provider/AnonymousAuthenticationProvider.php b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
index 92f668d..821e17e 100644
--- a/Authentication/Provider/AnonymousAuthenticationProvider.php
+++ b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
@@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Provider;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Exception\BadCredentialsException;
-use Symfony\Component\Security\Authentication\Token\AnonymousToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
/**
* AnonymousAuthenticationProvider validates AnonymousToken instances.
diff --git a/Authentication/Provider/AuthenticationProviderInterface.php b/Core/Authentication/Provider/AuthenticationProviderInterface.php
index 843f05c..89d5ed5 100644
--- a/Authentication/Provider/AuthenticationProviderInterface.php
+++ b/Core/Authentication/Provider/AuthenticationProviderInterface.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Provider;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
/**
* AuthenticationProviderInterface is the interface for for all authentication
diff --git a/Authentication/Provider/DaoAuthenticationProvider.php b/Core/Authentication/Provider/DaoAuthenticationProvider.php
index 69ef9a3..398f586 100644
--- a/Authentication/Provider/DaoAuthenticationProvider.php
+++ b/Core/Authentication/Provider/DaoAuthenticationProvider.php
@@ -9,17 +9,17 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Provider;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Encoder\EncoderFactoryInterface;
-use Symfony\Component\Security\User\UserProviderInterface;
-use Symfony\Component\Security\User\AccountCheckerInterface;
-use Symfony\Component\Security\User\AccountInterface;
-use Symfony\Component\Security\Exception\UsernameNotFoundException;
-use Symfony\Component\Security\Exception\AuthenticationServiceException;
-use Symfony\Component\Security\Exception\BadCredentialsException;
-use Symfony\Component\Security\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
/**
* DaoAuthenticationProvider uses a UserProviderInterface to retrieve the user
diff --git a/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
index 850b1ec..7fda9d4 100644
--- a/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
+++ b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
@@ -9,14 +9,14 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Provider;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
-use Symfony\Component\Security\User\AccountInterface;
-use Symfony\Component\Security\User\UserProviderInterface;
-use Symfony\Component\Security\User\AccountCheckerInterface;
-use Symfony\Component\Security\Exception\BadCredentialsException;
-use Symfony\Component\Security\Authentication\Token\PreAuthenticatedToken;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Processes a pre-authenticated authentication request.
diff --git a/Authentication/Provider/RememberMeAuthenticationProvider.php b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php
index d2d0268..95ee588 100644
--- a/Authentication/Provider/RememberMeAuthenticationProvider.php
+++ b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php
@@ -1,11 +1,11 @@
<?php
-namespace Symfony\Component\Security\Authentication\Provider;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
-use Symfony\Component\Security\User\AccountCheckerInterface;
-use Symfony\Component\Security\User\AccountInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Authentication\Token\RememberMeToken;
-use Symfony\Component\Security\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
class RememberMeAuthenticationProvider implements AuthenticationProviderInterface
{
diff --git a/Authentication/Provider/UserAuthenticationProvider.php b/Core/Authentication/Provider/UserAuthenticationProvider.php
index fa678b7..6947de3 100644
--- a/Authentication/Provider/UserAuthenticationProvider.php
+++ b/Core/Authentication/Provider/UserAuthenticationProvider.php
@@ -9,16 +9,16 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Provider;
-
-use Symfony\Component\Security\User\AccountInterface;
-use Symfony\Component\Security\User\AccountCheckerInterface;
-use Symfony\Component\Security\Exception\UsernameNotFoundException;
-use Symfony\Component\Security\Exception\AuthenticationException;
-use Symfony\Component\Security\Exception\BadCredentialsException;
-use Symfony\Component\Security\Exception\AuthenticationServiceException;
-use Symfony\Component\Security\Authentication\Token\UsernamePasswordToken;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+namespace Symfony\Component\Security\Core\Authentication\Provider;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* UserProviderInterface retrieves users for UsernamePasswordToken tokens.
diff --git a/Authentication/RememberMe/InMemoryTokenProvider.php b/Core/Authentication/RememberMe/InMemoryTokenProvider.php
index 71c1bf2..80c10d1 100644
--- a/Authentication/RememberMe/InMemoryTokenProvider.php
+++ b/Core/Authentication/RememberMe/InMemoryTokenProvider.php
@@ -1,8 +1,8 @@
<?php
-namespace Symfony\Component\Security\Authentication\RememberMe;
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
-use Symfony\Component\Security\Exception\TokenNotFoundException;
+use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
/**
* This class is used for testing purposes, and is not really suited for production.
diff --git a/Authentication/RememberMe/PersistentToken.php b/Core/Authentication/RememberMe/PersistentToken.php
index cdbc296..9b9bb93 100644
--- a/Authentication/RememberMe/PersistentToken.php
+++ b/Core/Authentication/RememberMe/PersistentToken.php
@@ -1,6 +1,6 @@
<?php
-namespace Symfony\Component\Security\Authentication\RememberMe;
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
/*
* This file is part of the Symfony package.
diff --git a/Authentication/RememberMe/PersistentTokenInterface.php b/Core/Authentication/RememberMe/PersistentTokenInterface.php
index 5525a34..3696d1f 100644
--- a/Authentication/RememberMe/PersistentTokenInterface.php
+++ b/Core/Authentication/RememberMe/PersistentTokenInterface.php
@@ -1,6 +1,6 @@
<?php
-namespace Symfony\Component\Security\Authentication\RememberMe;
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
/*
* This file is part of the Symfony package.
diff --git a/Authentication/RememberMe/TokenProviderInterface.php b/Core/Authentication/RememberMe/TokenProviderInterface.php
index 0ed3f50..e77e68a 100644
--- a/Authentication/RememberMe/TokenProviderInterface.php
+++ b/Core/Authentication/RememberMe/TokenProviderInterface.php
@@ -1,6 +1,6 @@
<?php
-namespace Symfony\Component\Security\Authentication\RememberMe;
+namespace Symfony\Component\Security\Core\Authentication\RememberMe;
/*
* This file is part of the Symfony package.
diff --git a/Authentication/Token/AnonymousToken.php b/Core/Authentication/Token/AnonymousToken.php
index 68174ff..7735925 100644
--- a/Authentication/Token/AnonymousToken.php
+++ b/Core/Authentication/Token/AnonymousToken.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
/**
* AnonymousToken represents an anonymous token.
diff --git a/Authentication/Token/PreAuthenticatedToken.php b/Core/Authentication/Token/PreAuthenticatedToken.php
index 0980ae6..c84ea10 100644
--- a/Authentication/Token/PreAuthenticatedToken.php
+++ b/Core/Authentication/Token/PreAuthenticatedToken.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
/**
* PreAuthenticatedToken implements a pre-authenticated token.
diff --git a/Authentication/Token/RememberMeToken.php b/Core/Authentication/Token/RememberMeToken.php
index f006a3a..81bf1e0 100644
--- a/Authentication/Token/RememberMeToken.php
+++ b/Core/Authentication/Token/RememberMeToken.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
-use Symfony\Component\Security\Authentication\RememberMe\PersistentTokenInterface;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentTokenInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
/**
* Base class for "Remember Me" tokens
diff --git a/Authentication/Token/Token.php b/Core/Authentication/Token/Token.php
index 9e0d5a1..d41bab5 100644
--- a/Authentication/Token/Token.php
+++ b/Core/Authentication/Token/Token.php
@@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
-use Symfony\Component\Security\Role\RoleInterface;
-use Symfony\Component\Security\Role\Role;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\Role\RoleInterface;
+use Symfony\Component\Security\Core\Role\Role;
+use Symfony\Component\Security\Core\User\AccountInterface;
/**
* Base class for Token instances.
diff --git a/Authentication/Token/TokenInterface.php b/Core/Authentication/Token/TokenInterface.php
index 99aa7a1..b6ac31c 100644
--- a/Authentication/Token/TokenInterface.php
+++ b/Core/Authentication/Token/TokenInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
/**
* TokenInterface is the interface for the user authentication information.
diff --git a/Authentication/Token/UsernamePasswordToken.php b/Core/Authentication/Token/UsernamePasswordToken.php
index 1794481..a61acd4 100644
--- a/Authentication/Token/UsernamePasswordToken.php
+++ b/Core/Authentication/Token/UsernamePasswordToken.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authentication\Token;
+namespace Symfony\Component\Security\Core\Authentication\Token;
/**
* UsernamePasswordToken implements a username and password token.
diff --git a/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php
index 5e4d15c..d6e642c 100644
--- a/Authorization/AccessDecisionManager.php
+++ b/Core/Authorization/AccessDecisionManager.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization;
+namespace Symfony\Component\Security\Core\Authorization;
-use Symfony\Component\Security\Authorization\Voter\VoterInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AccessDecisionManager is the base class for all access decision managers
diff --git a/Authorization/AccessDecisionManagerInterface.php b/Core/Authorization/AccessDecisionManagerInterface.php
index a11f25b..7648a3b 100644
--- a/Authorization/AccessDecisionManagerInterface.php
+++ b/Core/Authorization/AccessDecisionManagerInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization;
+namespace Symfony\Component\Security\Core\Authorization;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AccessDecisionManagerInterface makes authorization decisions.
diff --git a/Authorization/Voter/AuthenticatedVoter.php b/Core/Authorization/Voter/AuthenticatedVoter.php
index afda920..a400e4d 100644
--- a/Authorization/Voter/AuthenticatedVoter.php
+++ b/Core/Authorization/Voter/AuthenticatedVoter.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization\Voter;
+namespace Symfony\Component\Security\Core\Authorization\Voter;
-use Symfony\Component\Security\Authentication\AuthenticationTrustResolverInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AuthenticatedVoter votes if an attribute like IS_AUTHENTICATED_FULLY,
diff --git a/Authorization/Voter/RoleHierarchyVoter.php b/Core/Authorization/Voter/RoleHierarchyVoter.php
index 34a299c..7bdff3d 100644
--- a/Authorization/Voter/RoleHierarchyVoter.php
+++ b/Core/Authorization/Voter/RoleHierarchyVoter.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization\Voter;
+namespace Symfony\Component\Security\Core\Authorization\Voter;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
-use Symfony\Component\Security\Role\RoleHierarchyInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
* RoleHierarchyVoter uses a RoleHierarchy to determine the roles granted to
diff --git a/Authorization/Voter/RoleVoter.php b/Core/Authorization/Voter/RoleVoter.php
index e13c83b..426093a 100644
--- a/Authorization/Voter/RoleVoter.php
+++ b/Core/Authorization/Voter/RoleVoter.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization\Voter;
+namespace Symfony\Component\Security\Core\Authorization\Voter;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* RoleVoter votes if any attribute starts with a given prefix.
diff --git a/Authorization/Voter/VoterInterface.php b/Core/Authorization/Voter/VoterInterface.php
index 0c20fc0..add6e19 100644
--- a/Authorization/Voter/VoterInterface.php
+++ b/Core/Authorization/Voter/VoterInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Authorization\Voter;
+namespace Symfony\Component\Security\Core\Authorization\Voter;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* VoterInterface is the interface implemented by all voters.
diff --git a/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
index 8b63c63..01f471c 100644
--- a/Encoder/BasePasswordEncoder.php
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
/**
* BasePasswordEncoder is the base class for all password encoders.
diff --git a/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php
index ae33fee..0f218fe 100644
--- a/Encoder/EncoderFactory.php
+++ b/Core/Encoder/EncoderFactory.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
/**
* A generic encoder factory implementation
diff --git a/Encoder/EncoderFactoryInterface.php b/Core/Encoder/EncoderFactoryInterface.php
index 1ed37d7..2bdf6fc 100644
--- a/Encoder/EncoderFactoryInterface.php
+++ b/Core/Encoder/EncoderFactoryInterface.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
-use Symfony\Component\Security\User\AccountInterface;
+use Symfony\Component\Security\Core\User\AccountInterface;
/**
* EncoderFactoryInterface to support different encoders for different accounts.
diff --git a/Encoder/MessageDigestPasswordEncoder.php b/Core/Encoder/MessageDigestPasswordEncoder.php
index 752b9a7..811dd4c 100644
--- a/Encoder/MessageDigestPasswordEncoder.php
+++ b/Core/Encoder/MessageDigestPasswordEncoder.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
/**
* MessageDigestPasswordEncoder uses a message digest algorithm.
diff --git a/Encoder/PasswordEncoderInterface.php b/Core/Encoder/PasswordEncoderInterface.php
index af076ec..393b779 100644
--- a/Encoder/PasswordEncoderInterface.php
+++ b/Core/Encoder/PasswordEncoderInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
/**
* PasswordEncoderInterface is the interface for all encoders.
diff --git a/Encoder/PlaintextPasswordEncoder.php b/Core/Encoder/PlaintextPasswordEncoder.php
index 0cc6f2c..98982b0 100644
--- a/Encoder/PlaintextPasswordEncoder.php
+++ b/Core/Encoder/PlaintextPasswordEncoder.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Encoder;
+namespace Symfony\Component\Security\Core\Encoder;
/**
* PlaintextPasswordEncoder does not do any encoding.
diff --git a/Exception/AccessDeniedException.php b/Core/Exception/AccessDeniedException.php
index 67e2984..d065ed7 100644
--- a/Exception/AccessDeniedException.php
+++ b/Core/Exception/AccessDeniedException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AccessDeniedException is thrown when the account has not the required role.
diff --git a/Exception/AccountExpiredException.php b/Core/Exception/AccountExpiredException.php
index 8558edf..f0a09f7 100644
--- a/Exception/AccountExpiredException.php
+++ b/Core/Exception/AccountExpiredException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AccountExpiredException is thrown when the user account has expired.
diff --git a/Exception/AccountStatusException.php b/Core/Exception/AccountStatusException.php
index f00a110..4828d20 100644
--- a/Exception/AccountStatusException.php
+++ b/Core/Exception/AccountStatusException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AccountStatusException is the base class for authentication exceptions
diff --git a/Exception/AuthenticationCredentialsNotFoundException.php b/Core/Exception/AuthenticationCredentialsNotFoundException.php
index d4d62a2..4f95127 100644
--- a/Exception/AuthenticationCredentialsNotFoundException.php
+++ b/Core/Exception/AuthenticationCredentialsNotFoundException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AuthenticationCredentialsNotFoundException is thrown when an authentication is rejected
diff --git a/Exception/AuthenticationException.php b/Core/Exception/AuthenticationException.php
index 59203b6..a43b998 100644
--- a/Exception/AuthenticationException.php
+++ b/Core/Exception/AuthenticationException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AuthenticationException is the base class for all authentication exceptions.
diff --git a/Exception/AuthenticationServiceException.php b/Core/Exception/AuthenticationServiceException.php
index c1b34dd..02fcc2f 100644
--- a/Exception/AuthenticationServiceException.php
+++ b/Core/Exception/AuthenticationServiceException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* AuthenticationServiceException is thrown when an authentication request could not be processed due to a system problem.
diff --git a/Exception/BadCredentialsException.php b/Core/Exception/BadCredentialsException.php
index 9319041..797a806 100644
--- a/Exception/BadCredentialsException.php
+++ b/Core/Exception/BadCredentialsException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* BadCredentialsException is thrown when the user credentials are invalid.
diff --git a/Exception/CookieTheftException.php b/Core/Exception/CookieTheftException.php
index a69ccdf..64a06ca 100644
--- a/Exception/CookieTheftException.php
+++ b/Core/Exception/CookieTheftException.php
@@ -1,6 +1,6 @@
<?php
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/*
* This file is part of the Symfony package.
diff --git a/Exception/CredentialsExpiredException.php b/Core/Exception/CredentialsExpiredException.php
index 8a90e3e..43ba982 100644
--- a/Exception/CredentialsExpiredException.php
+++ b/Core/Exception/CredentialsExpiredException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* CredentialsExpiredException is thrown when the user account credentials have expired.
diff --git a/Exception/DisabledException.php b/Core/Exception/DisabledException.php
index 440d20e..fd87947 100644
--- a/Exception/DisabledException.php
+++ b/Core/Exception/DisabledException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* DisabledException is thrown when the user account is disabled.
diff --git a/Exception/InsufficientAuthenticationException.php b/Core/Exception/InsufficientAuthenticationException.php
index c0c5167..3fbba35 100644
--- a/Exception/InsufficientAuthenticationException.php
+++ b/Core/Exception/InsufficientAuthenticationException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* InsufficientAuthenticationException is thrown if the user credentials are not sufficiently trusted.
diff --git a/Exception/LockedException.php b/Core/Exception/LockedException.php
index 3b52ac7..8ea820f 100644
--- a/Exception/LockedException.php
+++ b/Core/Exception/LockedException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* LockedException is thrown if the user account is locked.
diff --git a/Exception/NonceExpiredException.php b/Core/Exception/NonceExpiredException.php
index 931f6a2..5e6a0c5 100644
--- a/Exception/NonceExpiredException.php
+++ b/Core/Exception/NonceExpiredException.php
@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpKernel\Security\EntryPoint;
-use Symfony\Component\Security\Exception\AuthenticationException;
-use Symfony\Component\Security\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
diff --git a/Exception/ProviderNotFoundException.php b/Core/Exception/ProviderNotFoundException.php
index 31a0b72..50112c5 100644
--- a/Exception/ProviderNotFoundException.php
+++ b/Core/Exception/ProviderNotFoundException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* ProviderNotFoundException is thrown when no AuthenticationProviderInterface instance
diff --git a/Exception/TokenNotFoundException.php b/Core/Exception/TokenNotFoundException.php
index 65d2d2a..1c13421 100644
--- a/Exception/TokenNotFoundException.php
+++ b/Core/Exception/TokenNotFoundException.php
@@ -1,5 +1,5 @@
<?php
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/*
* This file is part of the Symfony package.
diff --git a/Exception/UnsupportedAccountException.php b/Core/Exception/UnsupportedAccountException.php
index 723e397..0704b65 100644
--- a/Exception/UnsupportedAccountException.php
+++ b/Core/Exception/UnsupportedAccountException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* This exception is thrown when an account is reloaded from a provider which
diff --git a/Exception/UsernameNotFoundException.php b/Core/Exception/UsernameNotFoundException.php
index c6fcb18..a1733fe 100644
--- a/Exception/UsernameNotFoundException.php
+++ b/Core/Exception/UsernameNotFoundException.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Exception;
+namespace Symfony\Component\Security\Core\Exception;
/**
* UsernameNotFoundException is thrown if a User cannot be found by its username.
diff --git a/Role/Role.php b/Core/Role/Role.php
index 2f2b066..20e4fd5 100644
--- a/Role/Role.php
+++ b/Core/Role/Role.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Role;
+namespace Symfony\Component\Security\Core\Role;
/**
* Role is a simple implementation of a RoleInterface where the role is a
diff --git a/Role/RoleHierarchy.php b/Core/Role/RoleHierarchy.php
index a2eeb43..9556801 100644
--- a/Role/RoleHierarchy.php
+++ b/Core/Role/RoleHierarchy.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Role;
+namespace Symfony\Component\Security\Core\Role;
/**
* RoleHierarchy defines a role hierarchy.
diff --git a/Role/RoleHierarchyInterface.php b/Core/Role/RoleHierarchyInterface.php
index 0937b37..9f5cd5d 100644
--- a/Role/RoleHierarchyInterface.php
+++ b/Core/Role/RoleHierarchyInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Role;
+namespace Symfony\Component\Security\Core\Role;
/**
* RoleHierarchyInterface is the interface for a role hierarchy.
diff --git a/Role/RoleInterface.php b/Core/Role/RoleInterface.php
index e958466..923a933 100644
--- a/Role/RoleInterface.php
+++ b/Core/Role/RoleInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Role;
+namespace Symfony\Component\Security\Core\Role;
/**
* RoleInterface represents a role granted to a user.
diff --git a/Role/SwitchUserRole.php b/Core/Role/SwitchUserRole.php
index df6d1eb..589129c 100644
--- a/Role/SwitchUserRole.php
+++ b/Core/Role/SwitchUserRole.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\Role;
+namespace Symfony\Component\Security\Core\Role;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* SwitchUserRole is used when the current user temporarily impersonates
diff --git a/SecurityContext.php b/Core/SecurityContext.php
index 47a4587..405ace9 100644
--- a/SecurityContext.php
+++ b/Core/SecurityContext.php
@@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security;
+namespace Symfony\Component\Security\Core;
-use Symfony\Component\Security\Authorization\AccessDecisionManagerInterface;
-use Symfony\Component\Security\Authentication\AuthenticationManagerInterface;
-use Symfony\Component\Security\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Acl\Voter\FieldVote;
/**
diff --git a/User/AccountChecker.php b/Core/User/AccountChecker.php
index 9e4012c..76befa6 100644
--- a/User/AccountChecker.php
+++ b/Core/User/AccountChecker.php
@@ -9,12 +9,12 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
-use Symfony\Component\Security\Exception\CredentialsExpiredException;
-use Symfony\Component\Security\Exception\LockedException;
-use Symfony\Component\Security\Exception\DisabledException;
-use Symfony\Component\Security\Exception\AccountExpiredException;
+use Symfony\Component\Security\Core\Exception\CredentialsExpiredException;
+use Symfony\Component\Security\Core\Exception\LockedException;
+use Symfony\Component\Security\Core\Exception\DisabledException;
+use Symfony\Component\Security\Core\Exception\AccountExpiredException;
/**
* AccountChecker checks the user account flags.
diff --git a/User/AccountCheckerInterface.php b/Core/User/AccountCheckerInterface.php
index 776a99d..cf0d68b 100644
--- a/User/AccountCheckerInterface.php
+++ b/Core/User/AccountCheckerInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
/**
* AccountCheckerInterface checks user account when authentication occurs.
diff --git a/User/AccountInterface.php b/Core/User/AccountInterface.php
index 0bc488f..1863302 100644
--- a/User/AccountInterface.php
+++ b/Core/User/AccountInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
/**
* AccountInterface is the interface that user classes must implement.
diff --git a/User/AdvancedAccountInterface.php b/Core/User/AdvancedAccountInterface.php
index d5b6ae3..654ccaf 100644
--- a/User/AdvancedAccountInterface.php
+++ b/Core/User/AdvancedAccountInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
/**
* AdvancedAccountInterface adds status flags to a regular account.
diff --git a/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php
index 082e9c9..cc15463 100644
--- a/User/InMemoryUserProvider.php
+++ b/Core/User/InMemoryUserProvider.php
@@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
-use Symfony\Component\Security\Exception\UsernameNotFoundException;
-use Symfony\Component\Security\Exception\UnsupportedAccountException;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\UnsupportedAccountException;
/**
* InMemoryUserProvider is a simple non persistent user provider.
@@ -93,6 +93,6 @@ class InMemoryUserProvider implements UserProviderInterface
*/
public function supportsClass($class)
{
- return $class === 'Symfony\Component\Security\User\User';
+ return $class === 'Symfony\Component\Security\Core\User\User';
}
}
diff --git a/User/User.php b/Core/User/User.php
index 338d43c..49f7042 100644
--- a/User/User.php
+++ b/Core/User/User.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
/**
* User is the user implementation used by the in-memory user provider.
diff --git a/User/UserProviderInterface.php b/Core/User/UserProviderInterface.php
index 926f575..70ba0d0 100644
--- a/User/UserProviderInterface.php
+++ b/Core/User/UserProviderInterface.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Security\User;
+namespace Symfony\Component\Security\Core\User;
/**
* UserProviderInterface is the implementation that all user provider must
diff --git a/Http/AccessMap.php b/Http/AccessMap.php
new file mode 100644
index 0000000..0db7f7c
--- /dev/null
+++ b/Http/AccessMap.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http;
+
+use Symfony\Component\HttpFoundation\RequestMatcherInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * AccessMap allows configuration of different access control rules for
+ * specific parts of the website.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccessMap
+{
+ protected $map = array();
+
+ /**
+ * Constructor.
+ *
+ * @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance
+ * @param array $roles An array of roles needed to access the resource
+ * @param string|null $channel The channel to enforce (http, https, or null)
+ */
+ public function add(RequestMatcherInterface $requestMatcher, array $roles = array(), $channel = null)
+ {
+ $this->map[] = array($requestMatcher, $roles, $channel);
+ }
+
+ public function getPatterns(Request $request)
+ {
+ foreach ($this->map as $elements) {
+ if (null === $elements[0] || $elements[0]->matches($request)) {
+ return array($elements[1], $elements[2]);
+ }
+ }
+
+ return array(null, null);
+ }
+}
diff --git a/Http/Authentication/AuthenticationFailureHandlerInterface.php b/Http/Authentication/AuthenticationFailureHandlerInterface.php
new file mode 100644
index 0000000..4957edf
--- /dev/null
+++ b/Http/Authentication/AuthenticationFailureHandlerInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Symfony\Component\Security\Http\Authentication;
+
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+interface AuthenticationFailureHandlerInterface
+{
+ function onAuthenticationFailure(EventInterface $event, Request $request, \Exception $exception);
+} \ No newline at end of file
diff --git a/Http/Authentication/AuthenticationSuccessHandlerInterface.php b/Http/Authentication/AuthenticationSuccessHandlerInterface.php
new file mode 100644
index 0000000..6efa309
--- /dev/null
+++ b/Http/Authentication/AuthenticationSuccessHandlerInterface.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Symfony\Component\Security\Http\Authentication;
+
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+interface AuthenticationSuccessHandlerInterface
+{
+ function onAuthenticationSuccess(EventInterface $event, Request $request, TokenInterface $token);
+} \ No newline at end of file
diff --git a/Http/EntryPoint/BasicAuthenticationEntryPoint.php b/Http/EntryPoint/BasicAuthenticationEntryPoint.php
new file mode 100644
index 0000000..26bc305
--- /dev/null
+++ b/Http/EntryPoint/BasicAuthenticationEntryPoint.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\EntryPoint;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * BasicAuthenticationEntryPoint starts an HTTP Basic authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class BasicAuthenticationEntryPoint implements AuthenticationEntryPointInterface
+{
+ protected $realmName;
+
+ public function __construct($realmName)
+ {
+ $this->realmName = $realmName;
+ }
+
+ public function start(Request $request, AuthenticationException $authException = null)
+ {
+ $response = new Response();
+ $response->headers->set('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realmName));
+ $response->setStatusCode(401, $authException->getMessage());
+
+ return $response;
+ }
+}
diff --git a/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/Http/EntryPoint/DigestAuthenticationEntryPoint.php
new file mode 100644
index 0000000..89ba465
--- /dev/null
+++ b/Http/EntryPoint/DigestAuthenticationEntryPoint.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\EntryPoint;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Core\Exception\NonceExpiredException;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+
+/**
+ * DigestAuthenticationEntryPoint starts an HTTP Digest authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterface
+{
+ protected $key;
+ protected $realmName;
+ protected $nonceValiditySeconds;
+ protected $logger;
+
+ public function __construct($realmName, $key, $nonceValiditySeconds = 300, LoggerInterface $logger = null)
+ {
+ $this->realmName = $realmName;
+ $this->key = $key;
+ $this->nonceValiditySeconds = $nonceValiditySeconds;
+ $this->logger = $logger;
+ }
+
+ public function start(Request $request, AuthenticationException $authException = null)
+ {
+ $expiryTime = microtime(true) + $this->nonceValiditySeconds * 1000;
+ $signatureValue = md5($expiryTime.':'.$this->key);
+ $nonceValue = $expiryTime.':'.$signatureValue;
+ $nonceValueBase64 = base64_encode($nonceValue);
+
+ $authenticateHeader = sprintf('Digest realm="%s", qop="auth", nonce="%s"', $this->realmName, $nonceValueBase64);
+
+ if ($authException instanceof NonceExpiredException) {
+ $authenticateHeader = $authenticateHeader.', stale="true"';
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('WWW-Authenticate header sent to user agent: "%s"', $authenticateHeader));
+ }
+
+ $response = new Response();
+ $response->headers->set('WWW-Authenticate', $authenticateHeader);
+ $response->setStatusCode(401, $authException->getMessage());
+
+ return $response;
+ }
+
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ public function getRealmName()
+ {
+ return $this->realmName;
+ }
+}
diff --git a/Http/EntryPoint/FormAuthenticationEntryPoint.php b/Http/EntryPoint/FormAuthenticationEntryPoint.php
new file mode 100644
index 0000000..0902507
--- /dev/null
+++ b/Http/EntryPoint/FormAuthenticationEntryPoint.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\EntryPoint;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Core\SecurityContext;
+
+/**
+ * FormAuthenticationEntryPoint starts an authentication via a login form.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface
+{
+ protected $loginPath;
+ protected $useForward;
+
+ /**
+ * Constructor
+ *
+ * @param string $loginPath The path to the login form
+ * @param Boolean $useForward Whether to forward or redirect to the login form
+ */
+ public function __construct($loginPath, $useForward = false)
+ {
+ $this->loginPath = $loginPath;
+ $this->useForward = (Boolean) $useForward;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function start(Request $request, AuthenticationException $authException = null)
+ {
+ if ($this->useForward) {
+ return $event->getSubject()->handle(Request::create($this->loginPath), HttpKernelInterface::SUB_REQUEST);
+ }
+
+ $response = new Response();
+ $response->setRedirect(0 !== strpos($this->loginPath, 'http') ? $request->getUriForPath($this->loginPath) : $this->loginPath, 302);
+
+ return $response;
+ }
+}
diff --git a/Http/EntryPoint/RetryAuthenticationEntryPoint.php b/Http/EntryPoint/RetryAuthenticationEntryPoint.php
new file mode 100644
index 0000000..eb32e8a
--- /dev/null
+++ b/Http/EntryPoint/RetryAuthenticationEntryPoint.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\EntryPoint;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * RetryAuthenticationEntryPoint redirects URL based on the configured scheme.
+ *
+ * This entry point is not intended to work with HTTP post requests.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class RetryAuthenticationEntryPoint implements AuthenticationEntryPointInterface
+{
+ protected $httpPort;
+ protected $httpsPort;
+
+ public function __construct($httpPort = 80, $httpsPort = 443)
+ {
+ $this->httpPort = $httpPort;
+ $this->httpsPort = $httpsPort;
+ }
+
+ public function start(Request $request, AuthenticationException $authException = null)
+ {
+ $scheme = $request->isSecure() ? 'http' : 'https';
+ if ('http' === $scheme && 80 != $this->httpPort) {
+ $port = ':'.$this->httpPort;
+ } elseif ('https' === $scheme && 443 != $this->httpPort) {
+ $port = ':'.$this->httpsPort;
+ } else {
+ $port = '';
+ }
+
+ $qs = $request->getQueryString();
+ if (null !== $qs) {
+ $qs = '?'.$qs;
+ }
+
+ $url = $scheme.'://'.$request->getHost().$port.$request->getScriptName().$request->getPathInfo().$qs;
+
+ $response = new Response();
+ $response->setRedirect($url, 301);
+
+ return $response;
+ }
+}
diff --git a/Http/ExceptionTranslation/AccessDeniedHandlerInterface.php b/Http/ExceptionTranslation/AccessDeniedHandlerInterface.php
new file mode 100644
index 0000000..ba9553e
--- /dev/null
+++ b/Http/ExceptionTranslation/AccessDeniedHandlerInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Symfony\Component\Security\Http\ExceptionTranslation;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+
+/**
+ * This is used by the ExceptionListener to translate an AccessDeniedException
+ * to a Response object.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface AccessDeniedHandlerInterface
+{
+ /**
+ * Handles an access denied failure.
+ *
+ * @param EventInterface $event
+ * @param Request $request
+ * @param AccessDeniedException $accessDeniedException
+ *
+ * @return Response may return null
+ */
+ function handle(EventInterface $event, Request $request, AccessDeniedException $accessDeniedException);
+} \ No newline at end of file
diff --git a/Http/Firewall.php b/Http/Firewall.php
new file mode 100644
index 0000000..64b345f
--- /dev/null
+++ b/Http/Firewall.php
@@ -0,0 +1,95 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http;
+
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Firewall uses a FirewallMap to register security listeners for the given
+ * request.
+ *
+ * It allows for different security strategies within the same application
+ * (a Basic authentication for the /api, and a web based authentication for
+ * everything else for instance).
+ *
+ * The handle method must be connected to the core.request event.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class Firewall
+{
+ protected $map;
+ protected $dispatcher;
+ protected $currentListeners;
+
+ /**
+ * Constructor.
+ *
+ * @param FirewallMap $map A FirewallMap instance
+ */
+ public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher)
+ {
+ $this->map = $map;
+ $this->dispatcher = $dispatcher;
+ $this->currentListeners = array();
+ }
+
+ /**
+ * Handles security.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
+ return;
+ }
+
+ $request = $event->get('request');
+
+ // disconnect all listeners from core.security to avoid the overhead
+ // of most listeners having to do this manually
+ $this->dispatcher->disconnect('core.security');
+
+ // ensure that listeners disconnect from wherever they have connected to
+ foreach ($this->currentListeners as $listener) {
+ $listener->unregister($this->dispatcher);
+ }
+
+ // register listeners for this firewall
+ list($listeners, $exception) = $this->map->getListeners($request);
+ if (null !== $exception) {
+ $exception->register($this->dispatcher);
+ }
+ foreach ($listeners as $listener) {
+ $listener->register($this->dispatcher);
+ }
+
+ // save current listener instances
+ $this->currentListeners = $listeners;
+ if (null !== $exception) {
+ $this->currentListeners[] = $exception;
+ }
+
+ // initiate the listener chain
+ $ret = $this->dispatcher->notifyUntil($event = new Event($request, 'core.security', array('request' => $request)));
+ if ($event->isProcessed()) {
+ $event->setProcessed();
+
+ return $ret;
+ }
+ }
+}
diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php
new file mode 100644
index 0000000..4bb205f
--- /dev/null
+++ b/Http/Firewall/AbstractAuthenticationListener.php
@@ -0,0 +1,285 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\EventDispatcher\Event;
+
+use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * The AbstractAuthenticationListener is the preferred base class for all
+ * browser-/HTTP-based authentication requests.
+ *
+ * Subclasses likely have to implement the following:
+ * - an TokenInterface to hold authentication related data
+ * - an AuthenticationProvider to perform the actual authentication of the
+ * token, retrieve the AccountInterface implementation from a database, and
+ * perform the specific account checks using the AccountChecker
+ *
+ * By default, this listener only is active for a specific path, e.g.
+ * /login_check. If you want to change this behavior, you can overwrite the
+ * requiresAuthentication() method.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+abstract class AbstractAuthenticationListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $authenticationManager;
+ protected $sessionStrategy;
+ protected $providerKey;
+ protected $eventDispatcher;
+ protected $options;
+ protected $successHandler;
+ protected $failureHandler;
+ protected $logger;
+ protected $rememberMeServices;
+
+ /**
+ * Constructor.
+ *
+ * @param SecurityContext $securityContext A SecurityContext instance
+ * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
+ * @param array $options An array of options for the processing of a successful, or failed authentication attempt
+ * @param LoggerInterface $logger A LoggerInterface instance
+ */
+ public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null)
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->securityContext = $securityContext;
+ $this->authenticationManager = $authenticationManager;
+ $this->sessionStrategy = $sessionStrategy;
+ $this->providerKey = $providerKey;
+ $this->successHandler = $successHandler;
+ $this->failureHandler = $failureHandler;
+ $this->options = array_merge(array(
+ 'check_path' => '/login_check',
+ 'login_path' => '/login',
+ 'always_use_default_target_path' => false,
+ 'default_target_path' => '/',
+ 'target_path_parameter' => '_target_path',
+ 'use_referer' => false,
+ 'failure_path' => null,
+ 'failure_forward' => false,
+ ), $options);
+ $this->logger = $logger;
+ }
+
+ /**
+ * Sets the RememberMeServices implementation to use
+ *
+ * @param RememberMeServicesInterface $rememberMeServices
+ */
+ public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
+ {
+ $this->rememberMeServices = $rememberMeServices;
+ }
+
+ /**
+ * Subscribe to the core.security event
+ *
+ * @param EventDispatcher $dispatcher An EventDispatcher instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+
+ $this->eventDispatcher = $dispatcher;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles form based authentication.
+ *
+ * @param Event $event An Event instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (!$this->requiresAuthentication($request)) {
+ return;
+ }
+
+ try {
+ if (null === $returnValue = $this->attemptAuthentication($request)) {
+ return;
+ }
+
+ if ($returnValue instanceof TokenInterface) {
+ $this->sessionStrategy->onAuthentication($request, $returnValue);
+
+ $response = $this->onSuccess($event, $request, $returnValue);
+ } else if ($returnValue instanceof Response) {
+ $response = $returnValue;
+ } else {
+ throw new \RuntimeException('attemptAuthentication() must either return a Response, an implementation of TokenInterface, or null.');
+ }
+ } catch (AuthenticationException $failed) {
+ $response = $this->onFailure($event, $request, $failed);
+ }
+
+ $event->setProcessed();
+
+ return $response;
+ }
+
+ /**
+ * Whether this request requires authentication.
+ *
+ * The default implementation only processed requests to a specific path,
+ * but a subclass could change this to only authenticate requests where a
+ * certain parameters is present.
+ *
+ * @param Request $request
+ *
+ * @return Boolean
+ */
+ protected function requiresAuthentication(Request $request)
+ {
+ return $this->options['check_path'] === $request->getPathInfo();
+ }
+
+ protected function onFailure($event, Request $request, \Exception $failed)
+ {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage()));
+ }
+
+ $this->securityContext->setToken(null);
+
+ if (null !== $this->failureHandler) {
+ return $this->failureHandler->onAuthenticationFailure($event, $request, $failed);
+ }
+
+ if (null === $this->options['failure_path']) {
+ $this->options['failure_path'] = $this->options['login_path'];
+ }
+
+ if ($this->options['failure_forward']) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path']));
+ }
+
+ $subRequest = Request::create($this->options['failure_path']);
+ $subRequest->attributes->set(SecurityContext::AUTHENTICATION_ERROR, $failed->getMessage());
+
+ return $event->getSubject()->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
+ } else {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path']));
+ }
+
+ $request->getSession()->set(SecurityContext::AUTHENTICATION_ERROR, $failed->getMessage());
+
+ $response = new Response();
+ $response->setRedirect(0 !== strpos($this->options['failure_path'], 'http') ? $request->getUriForPath($this->options['failure_path']) : $this->options['failure_path'], 302);
+
+ return $response;
+ }
+ }
+
+ protected function onSuccess(EventInterface $event, Request $request, TokenInterface $token)
+ {
+ if (null !== $this->logger) {
+ $this->logger->debug('User has been authenticated successfully');
+ }
+
+ $this->securityContext->setToken($token);
+
+ $session = $request->getSession();
+ $session->remove(SecurityContext::AUTHENTICATION_ERROR);
+ $session->remove(SecurityContext::LAST_USERNAME);
+
+ $this->eventDispatcher->notify(new Event($this, 'security.login_success', array('request' => $request, 'token' => $token)));
+
+ if (null !== $this->successHandler) {
+ $response = $this->successHandler->onAuthenticationSuccess($request, $token);
+ } else {
+ $response = new Response();
+ $path = $this->determineTargetUrl($request);
+ $response->setRedirect(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302);
+ }
+
+ if (null !== $this->rememberMeServices) {
+ $this->rememberMeServices->loginSuccess($request, $response, $token);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Builds the target URL according to the defined options.
+ *
+ * @param Request $request
+ *
+ * @return string
+ */
+ protected function determineTargetUrl(Request $request)
+ {
+ if ($this->options['always_use_default_target_path']) {
+ return $this->options['default_target_path'];
+ }
+
+ if ($targetUrl = $request->get($this->options['target_path_parameter'])) {
+ return $targetUrl;
+ }
+
+ $session = $request->getSession();
+ if ($targetUrl = $session->get('_security.target_path')) {
+ $session->remove('_security.target_path');
+
+ return $targetUrl;
+ }
+
+ if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) {
+ return $targetUrl;
+ }
+
+ return $this->options['default_target_path'];
+ }
+
+ /**
+ * Performs authentication.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return TokenInterface The authenticated token, or null if full authentication is not possible
+ *
+ * @throws AuthenticationException if the authentication fails
+ */
+ abstract protected function attemptAuthentication(Request $request);
+}
diff --git a/Http/Firewall/AccessListener.php b/Http/Firewall/AccessListener.php
new file mode 100644
index 0000000..4aa1c55
--- /dev/null
+++ b/Http/Firewall/AccessListener.php
@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\Security\Http\AccessMap;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+
+/**
+ * AccessListener enforces access control rules.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AccessListener implements ListenerInterface
+{
+ protected $context;
+ protected $accessDecisionManager;
+ protected $map;
+ protected $authManager;
+ protected $logger;
+
+ public function __construct(SecurityContext $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMap $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null)
+ {
+ $this->context = $context;
+ $this->accessDecisionManager = $accessDecisionManager;
+ $this->map = $map;
+ $this->authManager = $authManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a core.security listener to enforce authorization rules.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles access authorization.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ if (null === $token = $this->context->getToken()) {
+ throw new AuthenticationCredentialsNotFoundException('A Token was not found in the SecurityContext.');
+ }
+
+ $request = $event->get('request');
+
+ list($attributes, $channel) = $this->map->getPatterns($request);
+
+ if (null === $attributes) {
+ return;
+ }
+
+ if (!$token->isAuthenticated()) {
+ $token = $this->authManager->authenticate($token);
+ $this->context->setToken($token);
+ }
+
+ if (!$this->accessDecisionManager->decide($token, $attributes, $request)) {
+ throw new AccessDeniedException();
+ }
+ }
+}
diff --git a/Http/Firewall/AnonymousAuthenticationListener.php b/Http/Firewall/AnonymousAuthenticationListener.php
new file mode 100644
index 0000000..43ef9a9
--- /dev/null
+++ b/Http/Firewall/AnonymousAuthenticationListener.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
+
+/**
+ * AnonymousAuthenticationListener automatically addds a Token if none is
+ * already present.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class AnonymousAuthenticationListener implements ListenerInterface
+{
+ protected $context;
+ protected $key;
+ protected $logger;
+
+ public function __construct(SecurityContext $context, $key, LoggerInterface $logger = null)
+ {
+ $this->context = $context;
+ $this->key = $key;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a core.security listener to load the SecurityContext from the
+ * session.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles anonymous authentication.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (null !== $this->context->getToken()) {
+ return;
+ }
+
+ $this->context->setToken(new AnonymousToken($this->key, 'anon.', array()));
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Populated SecurityContext with an anonymous Token'));
+ }
+ }
+}
diff --git a/Http/Firewall/BasicAuthenticationListener.php b/Http/Firewall/BasicAuthenticationListener.php
new file mode 100644
index 0000000..5cedf49
--- /dev/null
+++ b/Http/Firewall/BasicAuthenticationListener.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+
+/**
+ * BasicAuthenticationListener implements Basic HTTP authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class BasicAuthenticationListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $authenticationManager;
+ protected $providerKey;
+ protected $authenticationEntryPoint;
+ protected $logger;
+ protected $ignoreFailure;
+
+ public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->securityContext = $securityContext;
+ $this->authenticationManager = $authenticationManager;
+ $this->providerKey = $providerKey;
+ $this->authenticationEntryPoint = $authenticationEntryPoint;
+ $this->logger = $logger;
+ $this->ignoreFailure = false;
+ }
+
+ /**
+ *
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles basic authentication.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (false === $username = $request->server->get('PHP_AUTH_USER', false)) {
+ return;
+ }
+
+ if (null !== $token = $this->securityContext->getToken()) {
+ if ($token->isImmutable()) {
+ return;
+ }
+
+ if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (string) $token === $username) {
+ return;
+ }
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Basic Authentication Authorization header found for user "%s"', $username));
+ }
+
+ try {
+ $token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->server->get('PHP_AUTH_PW'), $this->providerKey));
+ $this->securityContext->setToken($token);
+ } catch (AuthenticationException $failed) {
+ $this->securityContext->setToken(null);
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage()));
+ }
+
+ if ($this->ignoreFailure) {
+ return;
+ }
+
+ $event->setProcessed();
+
+ return $this->authenticationEntryPoint->start($request, $failed);
+ }
+ }
+}
diff --git a/Http/Firewall/ChannelListener.php b/Http/Firewall/ChannelListener.php
new file mode 100644
index 0000000..39f8eef
--- /dev/null
+++ b/Http/Firewall/ChannelListener.php
@@ -0,0 +1,88 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Http\AccessMap;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+
+/**
+ * ChannelListener switches the HTTP protocol based on the access control
+ * configuration.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class ChannelListener implements ListenerInterface
+{
+ protected $map;
+ protected $authenticationEntryPoint;
+ protected $logger;
+
+ public function __construct(AccessMap $map, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
+ {
+ $this->map = $map;
+ $this->authenticationEntryPoint = $authenticationEntryPoint;
+ $this->logger = $logger;
+ }
+
+ /**
+ *
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles channel management.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ list($attributes, $channel) = $this->map->getPatterns($request);
+
+ if ('https' === $channel && !$request->isSecure()) {
+ if (null !== $this->logger) {
+ $this->logger->debug('Redirecting to HTTPS');
+ }
+
+ $event->setProcessed();
+
+ return $this->authenticationEntryPoint->start($request);
+ }
+
+ if ('http' === $channel && $request->isSecure()) {
+ if (null !== $this->logger) {
+ $this->logger->debug('Redirecting to HTTP');
+ }
+
+ $event->setProcessed();
+
+ return $this->authenticationEntryPoint->start($request);
+ }
+ }
+}
diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php
new file mode 100644
index 0000000..edc2f8c
--- /dev/null
+++ b/Http/Firewall/ContextListener.php
@@ -0,0 +1,175 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Exception\UnsupportedAccountException;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/**
+ * ContextListener manages the SecurityContext persistence through a session.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ContextListener implements ListenerInterface
+{
+ protected $context;
+ protected $contextKey;
+ protected $logger;
+ protected $userProviders;
+
+ public function __construct(SecurityContext $context, array $userProviders, $contextKey, LoggerInterface $logger = null)
+ {
+ if (empty($contextKey)) {
+ throw new \InvalidArgumentException('$contextKey must not be empty.');
+ }
+
+ $this->context = $context;
+ $this->userProviders = $userProviders;
+ $this->contextKey = $contextKey;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a core.security listener to load the SecurityContext from the
+ * session.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'read'), 0);
+ $dispatcher->connect('core.response', array($this, 'write'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->disconnect('core.response', array($this, 'write'));
+ }
+
+ /**
+ * Reads the SecurityContext from the session.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function read(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ $session = $request->hasSession() ? $request->getSession() : null;
+
+ if (null === $session || null === $token = $session->get('_security_'.$this->contextKey)) {
+ $this->context->setToken(null);
+ } else {
+ if (null !== $this->logger) {
+ $this->logger->debug('Read SecurityContext from the session');
+ }
+
+ $token = unserialize($token);
+
+ if (null !== $token && false === $token->isImmutable()) {
+ $token = $this->refreshUser($token);
+ }
+
+ $this->context->setToken($token);
+ }
+ }
+
+ /**
+ * Writes the SecurityContext to the session.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function write(EventInterface $event, Response $response)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
+ return $response;
+ }
+
+ if (null === $token = $this->context->getToken()) {
+ return $response;
+ }
+
+ if (null === $token || $token instanceof AnonymousToken) {
+ return $response;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Write SecurityContext in the session');
+ }
+
+ $event->get('request')->getSession()->set('_security_'.$this->contextKey, serialize($token));
+
+ return $response;
+ }
+
+ /**
+ * Refreshes the user by reloading it from the user provider
+ *
+ * @param TokenInterface $token
+ *
+ * @return TokenInterface|null
+ */
+ protected function refreshUser(TokenInterface $token)
+ {
+ $user = $token->getUser();
+ if (!$user instanceof AccountInterface) {
+ return $token;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Reloading user from user provider.'));
+ }
+
+ foreach ($this->userProviders as $provider) {
+ try {
+ $cUser = $provider->loadUserByAccount($user);
+
+ $token->setRoles($cUser->getRoles());
+ $token->setUser($cUser);
+
+ if (false === $cUser->equals($user)) {
+ $token->setAuthenticated(false);
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user));
+ }
+
+ return $token;
+ } catch (UnsupportedAccountException $unsupported) {
+ // let's try the next user provider
+ } catch (UsernameNotFoundException $notFound) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Username "%s" could not be found.', $user));
+ }
+
+ return null;
+ }
+ }
+
+ throw new \RuntimeException(sprintf('There is no user provider for user "%s".', get_class($user)));
+ }
+}
diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php
new file mode 100644
index 0000000..ea6a880
--- /dev/null
+++ b/Http/Firewall/DigestAuthenticationListener.php
@@ -0,0 +1,239 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Http\EntryPoint\NonceExpiredException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+
+/**
+ * DigestAuthenticationListener implements Digest HTTP authentication.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class DigestAuthenticationListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $provider;
+ protected $providerKey;
+ protected $authenticationEntryPoint;
+ protected $logger;
+
+ public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null)
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->securityContext = $securityContext;
+ $this->provider = $provider;
+ $this->providerKey = $providerKey;
+ $this->authenticationEntryPoint = $authenticationEntryPoint;
+ $this->logger = $logger;
+ }
+
+ /**
+ *
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles digest authentication.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (!$header = $request->server->get('PHP_AUTH_DIGEST')) {
+ return;
+ }
+
+ if (null !== $token = $this->securityContext->getToken()) {
+ if ($token->isImmutable()) {
+ return;
+ }
+
+ if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (string) $token === $username) {
+ return;
+ }
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Digest Authorization header received from user agent: %s', $header));
+ }
+
+ $digestAuth = new DigestData($header);
+
+ try {
+ $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName());
+ } catch (BadCredentialsException $e) {
+ $this->fail($request, $e);
+
+ return;
+ }
+
+ try {
+ $user = $this->provider->loadUserByUsername($digestAuth->getUsername());
+
+ if (null === $user) {
+ throw new AuthenticationServiceException('AuthenticationDao returned null, which is an interface contract violation');
+ }
+
+ $serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod());
+ } catch (UsernameNotFoundException $notFound) {
+ $this->fail($request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername())));
+
+ return;
+ }
+
+ if ($serverDigestMd5 !== $digestAuth->getResponse()) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf("Expected response: '%s' but received: '%s'; is AuthenticationDao returning clear text passwords?", $serverDigestMd5, $digestAuth->getResponse()));
+ }
+
+ $this->fail($request, new BadCredentialsException('Incorrect response'));
+
+ return;
+ }
+
+ if ($digestAuth->isNonceExpired()) {
+ $this->fail($request, new NonceExpiredException('Nonce has expired/timed out.'));
+
+ return;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse()));
+ }
+
+ $this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey));
+ }
+
+ protected function fail(Request $request, AuthenticationException $failed)
+ {
+ $this->securityContext->setToken(null);
+
+ if (null !== $this->logger) {
+ $this->logger->debug($failed);
+ }
+
+ $this->authenticationEntryPoint->start($request, $failed);
+ }
+}
+
+class DigestData
+{
+ protected $elements;
+ protected $header;
+ protected $nonceExpiryTime;
+
+ public function __construct($header)
+ {
+ $this->header = $header;
+ $parts = preg_split('/, /', $header);
+ $this->elements = array();
+ foreach ($parts as $part) {
+ list($key, $value) = explode('=', $part);
+ $this->elements[$key] = '"' === $value[0] ? substr($value, 1, -1) : $value;
+ }
+ }
+
+ public function getResponse()
+ {
+ return $this->elements['response'];
+ }
+
+ public function getUsername()
+ {
+ return $this->elements['username'];
+ }
+
+ public function validateAndDecode($entryPointKey, $expectedRealm)
+ {
+ if ($keys = array_diff(array('username', 'realm', 'nonce', 'uri', 'response'), array_keys($this->elements))) {
+ throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s" (%s)', $this->header, implode(', ', $keys)));
+ }
+
+ if ('auth' === $this->elements['qop']) {
+ if (!isset($this->elements['nc']) || !isset($this->elements['cnonce'])) {
+ throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s"', $this->header));
+ }
+ }
+
+ if ($expectedRealm !== $this->elements['realm']) {
+ throw new BadCredentialsException(sprintf('Response realm name "%s" does not match system realm name of "%s".', $this->elements['realm'], $expectedRealm));
+ }
+
+ if (false === $nonceAsPlainText = base64_decode($this->elements['nonce'])) {
+ throw new BadCredentialsException(sprintf('Nonce is not encoded in Base64; received nonce "%s".', $this->elements['nonce']));
+ }
+
+ $nonceTokens = explode(':', $nonceAsPlainText);
+
+ if (2 !== count($nonceTokens)) {
+ throw new BadCredentialsException(sprintf('Nonce should have yielded two tokens but was "%s".', $nonceAsPlainText));
+ }
+
+ $this->nonceExpiryTime = $nonceTokens[0];
+
+ if (md5($this->nonceExpiryTime.':'.$entryPointKey) !== $nonceTokens[1]) {
+ new BadCredentialsException(sprintf('Nonce token compromised "%s".', $nonceAsPlainText));
+ }
+ }
+
+ public function calculateServerDigest($password, $httpMethod)
+ {
+ $a2Md5 = md5(strtoupper($httpMethod).':'.$this->elements['uri']);
+ $a1Md5 = md5($this->elements['username'].':'.$this->elements['realm'].':'.$password);
+
+ $digest = $a1Md5.':'.$this->elements['nonce'];
+ if (!isset($this->elements['qop'])) {
+ } elseif ('auth' === $this->elements['qop']) {
+ $digest .= ':'.$this->elements['nc'].':'.$this->elements['cnonce'].':'.$this->elements['qop'];
+ } else {
+ throw new \InvalidArgumentException('This method does not support a qop: "%s".', $this->elements['qop']);
+ }
+ $digest .= ':'.$a2Md5;
+
+ return md5($digest);
+ }
+
+ public function isNonceExpired()
+ {
+ return $this->nonceExpiryTime < microtime(true);
+ }
+}
diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php
new file mode 100644
index 0000000..6d3aa6b
--- /dev/null
+++ b/Http/Firewall/ExceptionListener.php
@@ -0,0 +1,170 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\SecurityBundle\Security\AccessDeniedHandler;
+use Symfony\Component\Security\Http\ExceptionTranslation\AccessDeniedHandlerInterface;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authentication\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
+use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * ExceptionListener catches authentication exception and converts them to
+ * Response instances.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class ExceptionListener implements ListenerInterface
+{
+ protected $context;
+ protected $accessDeniedHandler;
+ protected $authenticationEntryPoint;
+ protected $authenticationTrustResolver;
+ protected $errorPage;
+ protected $logger;
+
+ public function __construct(SecurityContext $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null)
+ {
+ $this->context = $context;
+ $this->accessDeniedHandler = $accessDeniedHandler;
+ $this->authenticationEntryPoint = $authenticationEntryPoint;
+ $this->authenticationTrustResolver = $trustResolver;
+ $this->errorPage = $errorPage;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a core.exception listener to take care of security exceptions.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.exception', array($this, 'handleException'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->disconnect('core.exception', array($this, 'handleException'));
+ }
+
+ /**
+ * Handles security related exceptions.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handleException(EventInterface $event)
+ {
+ $exception = $event->get('exception');
+ $request = $event->get('request');
+
+ if ($exception instanceof AuthenticationException) {
+ if (null !== $this->logger) {
+ $this->logger->info(sprintf('Authentication exception occurred; redirecting to authentication entry point (%s)', $exception->getMessage()));
+ }
+
+ try {
+ $response = $this->startAuthentication($request, $exception);
+ } catch (\Exception $e) {
+ $event->set('exception', $e);
+
+ return;
+ }
+ } elseif ($exception instanceof AccessDeniedException) {
+ $token = $this->context->getToken();
+ if (!$this->authenticationTrustResolver->isFullFledged($token)) {
+ if (null !== $this->logger) {
+ $this->logger->info('Access denied (user is not fully authenticated); redirecting to authentication entry point');
+ }
+
+ try {
+ $response = $this->startAuthentication($request, new InsufficientAuthenticationException('Full authentication is required to access this resource.', $token, 0, $exception));
+ } catch (\Exception $e) {
+ $event->set('exception', $e);
+
+ return;
+ }
+ } else {
+ if (null !== $this->logger) {
+ $this->logger->info('Access is denied (and user is neither anonymous, nor remember-me)');
+ }
+
+ try {
+ if (null !== $this->accessDeniedHandler) {
+ $response = $this->accessDeniedHandler->handle($event, $request, $exception);
+
+ if (!$response instanceof Response) {
+ return;
+ }
+ } else {
+ if (null === $this->errorPage) {
+ return;
+ }
+
+ $subRequest = Request::create($this->errorPage);
+ $subRequest->attributes->set(SecurityContext::ACCESS_DENIED_ERROR, $exception->getMessage());
+
+ $response = $event->getSubject()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
+ $response->setStatusCode(403);
+
+ return $response;
+ }
+ } catch (\Exception $e) {
+ if (null !== $this->logger) {
+ $this->logger->err(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage()));
+ }
+
+ $event->set('exception', new \RuntimeException('Exception thrown when handling an exception.', 0, $e));
+
+ return;
+ }
+ }
+ } else {
+ return;
+ }
+
+ $event->setProcessed();
+
+ return $response;
+ }
+
+ protected function startAuthentication(Request $request, AuthenticationException $reason)
+ {
+ $this->context->setToken(null);
+
+ if (null === $this->authenticationEntryPoint) {
+ throw $reason;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Calling Authentication entry point');
+ }
+
+ $request->getSession()->set('_security.target_path', $request->getUri());
+
+ return $this->authenticationEntryPoint->start($request, $reason);
+ }
+}
diff --git a/Http/Firewall/ListenerInterface.php b/Http/Firewall/ListenerInterface.php
new file mode 100644
index 0000000..afb2d9f
--- /dev/null
+++ b/Http/Firewall/ListenerInterface.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * Interface that must be implemented by firewall listeners
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface ListenerInterface
+{
+ /**
+ * The implementation must connect this listener to all necessary events.
+ *
+ * Typical events are: "core.security", and "core.response"
+ *
+ * @param EventDispatcherInterface $dispatcher
+ */
+ function register(EventDispatcherInterface $dispatcher);
+
+ /**
+ * The implementation must remove this listener from any events that it had
+ * connected to in register().
+ *
+ * It may remove this listener from "core.security", but this is ensured by
+ * the firewall anyway.
+ *
+ * @param EventDispatcherInterface $dispatcher
+ */
+ function unregister(EventDispatcherInterface $dispatcher);
+} \ No newline at end of file
diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php
new file mode 100644
index 0000000..fb4bac9
--- /dev/null
+++ b/Http/Firewall/LogoutListener.php
@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * LogoutListener logout users.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class LogoutListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $logoutPath;
+ protected $targetUrl;
+ protected $handlers;
+
+ /**
+ * Constructor
+ *
+ * @param SecurityContext $securityContext
+ * @param string $logoutPath The path that starts the logout process
+ * @param string $targetUrl The URL to redirect to after logout
+ */
+ public function __construct(SecurityContext $securityContext, $logoutPath, $targetUrl = '/')
+ {
+ $this->securityContext = $securityContext;
+ $this->logoutPath = $logoutPath;
+ $this->targetUrl = $targetUrl;
+ $this->handlers = array();
+ }
+
+ /**
+ * Adds a logout handler
+ *
+ * @param LogoutHandlerInterface $handler
+ * @return void
+ */
+ public function addHandler(LogoutHandlerInterface $handler)
+ {
+ $this->handlers[] = $handler;
+ }
+
+ /**
+ * Registers a core.security listener.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Performs the logout if requested
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if ($this->logoutPath !== $request->getPathInfo()) {
+ return;
+ }
+
+ $response = new Response();
+ $response->setRedirect(0 !== strpos($this->targetUrl, 'http') ? $request->getUriForPath($this->targetUrl) : $this->targetUrl, 302);
+
+ // handle multiple logout attempts gracefully
+ if ($token = $this->securityContext->getToken()) {
+ foreach ($this->handlers as $handler) {
+ $handler->logout($request, $response, $token);
+ }
+ }
+
+ $this->securityContext->setToken(null);
+
+ $event->setProcessed();
+
+ return $response;
+ }
+}
diff --git a/Http/Firewall/PreAuthenticatedListener.php b/Http/Firewall/PreAuthenticatedListener.php
new file mode 100644
index 0000000..b4160ea
--- /dev/null
+++ b/Http/Firewall/PreAuthenticatedListener.php
@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * PreAuthenticatedListener is the base class for all listener that
+ * authenticates users based on a pre-authenticated request (like a certificate
+ * for instance).
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+abstract class PreAuthenticatedListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $authenticationManager;
+ protected $providerKey;
+ protected $logger;
+
+ public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null)
+ {
+ $this->securityContext = $securityContext;
+ $this->authenticationManager = $authenticationManager;
+ $this->providerKey = $providerKey;
+ $this->logger = $logger;
+ }
+
+ /**
+ *
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles X509 authentication.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Checking secure context token: %s', $this->securityContext->getToken()));
+ }
+
+ list($user, $credentials) = $this->getPreAuthenticatedData($request);
+
+ if (null !== $token = $this->securityContext->getToken()) {
+ if ($token->isImmutable()) {
+ return;
+ }
+
+ if ($token instanceof PreAuthenticatedToken && $token->isAuthenticated() && (string) $token === $user) {
+ return;
+ }
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Trying to pre-authenticate user "%s"', $user));
+ }
+
+ try {
+ $token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey));
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Authentication success: %s', $token));
+ }
+ $this->securityContext->setToken($token);
+ } catch (AuthenticationException $failed) {
+ $this->securityContext->setToken(null);
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf("Cleared security context due to exception: %s", $failed->getMessage()));
+ }
+ }
+ }
+
+ /**
+ * Gets the user and credentials from the Request.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return array An array composed of the user and the credentials
+ */
+ abstract protected function getPreAuthenticatedData(Request $request);
+}
diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php
new file mode 100644
index 0000000..e083492
--- /dev/null
+++ b/Http/Firewall/RememberMeListener.php
@@ -0,0 +1,148 @@
+<?php
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\CookieTheftException;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * RememberMeListener implements authentication capabilities via a cookie
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class RememberMeListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $rememberMeServices;
+ protected $authenticationManager;
+ protected $logger;
+ protected $lastState;
+
+ /**
+ * Constructor
+ *
+ * @param SecurityContext $securityContext
+ * @param RememberMeServicesInterface $rememberMeServices
+ * @param AuthenticationManagerInterface $authenticationManager
+ * @param LoggerInterface $logger
+ */
+ public function __construct(SecurityContext $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null)
+ {
+ $this->securityContext = $securityContext;
+ $this->rememberMeServices = $rememberMeServices;
+ $this->authenticationManager = $authenticationManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Listen to core.security, and core.response event
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'checkCookies'), 0);
+ $dispatcher->connect('core.response', array($this, 'updateCookies'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->disconnect('core.response', array($this, 'updateCookies'));
+ }
+
+ /**
+ * Handles remember-me cookie based authentication.
+ *
+ * @param Event $event An Event instance
+ */
+ public function checkCookies(EventInterface $event)
+ {
+ $this->lastState = null;
+
+ if (null !== $this->securityContext->getToken()) {
+ return;
+ }
+
+ try {
+ if (null === $token = $this->rememberMeServices->autoLogin($event->get('request'))) {
+ return;
+ }
+
+ try {
+ if (null === $token = $this->authenticationManager->authenticate($token)) {
+ return;
+ }
+
+ $this->securityContext->setToken($token);
+
+ if (null !== $this->logger) {
+ $this->logger->debug('SecurityContext populated with remember-me token.');
+ }
+
+ $this->lastState = $token;
+ } catch (AuthenticationException $failed) {
+ if (null !== $this->logger) {
+ $this->logger->debug(
+ 'SecurityContext not populated with remember-me token as the'
+ .' AuthenticationManager rejected the AuthenticationToken returned'
+ .' by the RememberMeServices: '.$failed->getMessage()
+ );
+ }
+
+ $this->lastState = $failed;
+ }
+ } catch (AuthenticationException $cookieInvalid) {
+ $this->lastState = $cookieInvalid;
+
+ if (null !== $this->logger) {
+ $this->logger->debug('The presented cookie was invalid: '.$cookieInvalid->getMessage());
+ }
+
+ // silently ignore everything except a cookie theft exception
+ if ($cookieInvalid instanceof CookieTheftException) {
+ throw $cookieInvalid;
+ }
+ }
+ }
+
+ /**
+ * Update cookies
+ * @param Event $event
+ */
+ public function updateCookies(EventInterface $event, Response $response)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
+ return $response;
+ }
+
+ if ($this->lastState instanceof TokenInterface) {
+ $this->rememberMeServices->loginSuccess($event->get('request'), $response, $this->lastState);
+ } else if ($this->lastState instanceof AuthenticationException) {
+ $this->rememberMeServices->loginFail($event->get('request'), $response);
+ }
+
+ return $response;
+ }
+} \ No newline at end of file
diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php
new file mode 100644
index 0000000..e80f0e6
--- /dev/null
+++ b/Http/Firewall/SwitchUserListener.php
@@ -0,0 +1,184 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\User\AccountCheckerInterface;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Role\SwitchUserRole;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * SwitchUserListener allows a user to impersonate another one temporarly
+ * (like the Unix su command).
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class SwitchUserListener implements ListenerInterface
+{
+ protected $securityContext;
+ protected $provider;
+ protected $accountChecker;
+ protected $providerKey;
+ protected $accessDecisionManager;
+ protected $usernameParameter;
+ protected $role;
+ protected $logger;
+
+ /**
+ * Constructor.
+ */
+ public function __construct(SecurityContext $securityContext, UserProviderInterface $provider, AccountCheckerInterface $accountChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH')
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->securityContext = $securityContext;
+ $this->provider = $provider;
+ $this->accountChecker = $accountChecker;
+ $this->providerKey = $providerKey;
+ $this->accessDecisionManager = $accessDecisionManager;
+ $this->usernameParameter = $usernameParameter;
+ $this->role = $role;
+ $this->logger = $logger;
+ }
+
+ /**
+ *
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param integer $priority The priority
+ */
+ public function register(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->connect('core.security', array($this, 'handle'), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ }
+
+ /**
+ * Handles digest authentication.
+ *
+ * @param EventInterface $event An EventInterface instance
+ */
+ public function handle(EventInterface $event)
+ {
+ $request = $event->get('request');
+
+ if (!$request->get($this->usernameParameter)) {
+ return;
+ }
+
+ if ('_exit' === $request->get($this->usernameParameter)) {
+ $this->securityContext->setToken($this->attemptExitUser($request));
+ } else {
+ try {
+ $this->securityContext->setToken($this->attemptSwitchUser($request));
+ } catch (AuthenticationException $e) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Switch User failed: "%s"', $e->getMessage()));
+ }
+ }
+ }
+
+ $response = new Response();
+ $request->server->set('QUERY_STRING', '');
+ $response->setRedirect($request->getUri(), 302);
+
+ $event->setProcessed();
+
+ return $return;
+ }
+
+ /**
+ * Attempts to switch to another user.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return TokenInterface|null The new TokenInterface if successfully switched, null otherwise
+ */
+ protected function attemptSwitchUser(Request $request)
+ {
+ $token = $this->securityContext->getToken();
+ if (false !== $this->getOriginalToken($token)) {
+ throw new \LogicException(sprintf('You are already switched to "%s" user.', (string) $token));
+ }
+
+ $this->accessDecisionManager->decide($token, array($this->role));
+
+ $username = $request->get($this->usernameParameter);
+
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Attempt to switch to user "%s"', $username));
+ }
+
+ $user = $this->provider->loadUserByUsername($username);
+ $this->accountChecker->checkPostAuth($user);
+
+ $roles = $user->getRoles();
+ $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->securityContext->getToken());
+
+ $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles);
+ $token->setImmutable(true);
+
+ return $token;
+ }
+
+ /**
+ * Attempts to exit from an already switched user.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return TokenInterface The original TokenInterface instance
+ */
+ protected function attemptExitUser(Request $request)
+ {
+ if (false === $original = $this->getOriginalToken($this->securityContext->getToken())) {
+ throw new AuthenticationCredentialsNotFoundException(sprintf('Could not find original Token object.'));
+ }
+
+ return $original;
+ }
+
+ /**
+ * Gets the original Token from a switched one.
+ *
+ * @param TokenInterface $token A switched TokenInterface instance
+ *
+ * @return TokenInterface|false The original TokenInterface instance, false if the current TokenInterface is not switched
+ */
+ protected function getOriginalToken(TokenInterface $token)
+ {
+ foreach ($token->getRoles() as $role) {
+ if ($role instanceof SwitchUserRole) {
+ return $role->getSource();
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
new file mode 100644
index 0000000..e8ea6f9
--- /dev/null
+++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
@@ -0,0 +1,64 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
+use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+
+/**
+ * UsernamePasswordFormAuthenticationListener is the default implementation of
+ * an authentication via a simple form composed of a username and a password.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null)
+ {
+ parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array(
+ 'username_parameter' => '_username',
+ 'password_parameter' => '_password',
+ 'post_only' => true,
+ ), $options), $successHandler, $failureHandler, $logger);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function attemptAuthentication(Request $request)
+ {
+ if ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Authentication method not supported: %s.', $request->getMethod()));
+ }
+
+ return null;
+ }
+
+ $username = trim($request->get($this->options['username_parameter']));
+ $password = $request->get($this->options['password_parameter']);
+
+ $request->getSession()->set(SecurityContext::LAST_USERNAME, $username);
+
+ return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
+ }
+}
diff --git a/Http/Firewall/X509AuthenticationListener.php b/Http/Firewall/X509AuthenticationListener.php
new file mode 100644
index 0000000..8f755f5
--- /dev/null
+++ b/Http/Firewall/X509AuthenticationListener.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
+
+/**
+ * X509 authentication listener.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class X509AuthenticationListener extends PreAuthenticatedListener
+{
+ protected $userKey;
+ protected $credentialKey;
+
+ public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null)
+ {
+ parent::__construct($securityContext, $authenticationManager, $providerKey, $logger);
+
+ $this->userKey = $userKey;
+ $this->credentialKey = $credentialKey;
+ }
+
+ protected function getPreAuthenticatedData(Request $request)
+ {
+ if (!$request->server->has($this->userKey)) {
+ throw new BadCredentialsException(sprintf('SSL key was not found: %s', $this->userKey));
+ }
+
+ return array($request->server->get($this->userKey), $request->server->get($this->credentialKey, ''));
+ }
+}
diff --git a/Http/FirewallMap.php b/Http/FirewallMap.php
new file mode 100644
index 0000000..ac2a9f9
--- /dev/null
+++ b/Http/FirewallMap.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Symfony\Component\Security\Http;
+
+use Symfony\Component\HttpFoundation\RequestMatcherInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Security\Firewall\ExceptionListener;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * FirewallMap allows configuration of different firewalls for specific parts
+ * of the website.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class FirewallMap implements FirewallMapInterface
+{
+ protected $map = array();
+
+ public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null)
+ {
+ $this->map[] = array($requestMatcher, $listeners, $exceptionListener);
+ }
+
+ public function getListeners(Request $request)
+ {
+ foreach ($this->map as $elements) {
+ if (null === $elements[0] || $elements[0]->matches($request)) {
+ return array($elements[1], $elements[2]);
+ }
+ }
+
+ return array(array(), null);
+ }
+}
diff --git a/Http/FirewallMapInterface.php b/Http/FirewallMapInterface.php
new file mode 100644
index 0000000..575b96f
--- /dev/null
+++ b/Http/FirewallMapInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Symfony\Component\Security\Http;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * This interface must be implemented by firewall maps.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface FirewallMapInterface
+{
+ /**
+ * Returns the authentication listeners, and the exception listener to use
+ * for the given request.
+ *
+ * If there are no authentication listeners, the first inner are must be
+ * empty.
+ *
+ * If there is no exception listener, the second element of the outer array
+ * must be null.
+ *
+ * @param Request $request
+ * @return array of the format array(array(AuthenticationListener), ExceptionListener)
+ */
+ function getListeners(Request $request);
+} \ No newline at end of file
diff --git a/Http/Logout/CookieClearingLogoutHandler.php b/Http/Logout/CookieClearingLogoutHandler.php
new file mode 100644
index 0000000..ea6bff3
--- /dev/null
+++ b/Http/Logout/CookieClearingLogoutHandler.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Logout;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * This handler cleares the passed cookies when a user logs out.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class CookieClearingLogoutHandler implements LogoutHandlerInterface
+{
+ protected $cookieNames;
+
+ /**
+ * Constructor
+ * @param array $cookieNames An array of cookie names to unset
+ */
+ public function __construct(array $cookieNames)
+ {
+ $this->cookieNames = $cookieNames;
+ }
+
+ /**
+ * Returns the names of the cookies to unset
+ * @return array
+ */
+ public function getCookieNames()
+ {
+ return $this->cookieNames;
+ }
+
+ /**
+ * Implementation for the LogoutHandlerInterface. Deletes all requested cookies.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token
+ * @return void
+ */
+ public function logout(Request $request, Response $response, TokenInterface $token)
+ {
+ foreach ($this->cookieNames as $cookieName) {
+ $response->headers->clearCookie($cookieName);
+ }
+ }
+}
diff --git a/Http/Logout/LogoutHandlerInterface.php b/Http/Logout/LogoutHandlerInterface.php
new file mode 100644
index 0000000..86859f9
--- /dev/null
+++ b/Http/Logout/LogoutHandlerInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Logout;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface that needs to be implemented by LogoutHandlers.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface LogoutHandlerInterface
+{
+ /**
+ * This method is called by the LogoutListener when a user has requested
+ * to be logged out. Usually, you would unset session variables, or remove
+ * cookies, etc.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token
+ * @return void
+ */
+ function logout(Request $request, Response $response, TokenInterface $token);
+} \ No newline at end of file
diff --git a/Http/Logout/SessionLogoutHandler.php b/Http/Logout/SessionLogoutHandler.php
new file mode 100644
index 0000000..43fbaf1
--- /dev/null
+++ b/Http/Logout/SessionLogoutHandler.php
@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Logout;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Handler for clearing invalidating the current session.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class SessionLogoutHandler implements LogoutHandlerInterface
+{
+ /**
+ * Invalidate the current session
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token
+ * @return void
+ */
+ public function logout(Request $request, Response $response, TokenInterface $token)
+ {
+ $request->getSession()->invalidate();
+ }
+} \ No newline at end of file
diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
new file mode 100644
index 0000000..73e5863
--- /dev/null
+++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
@@ -0,0 +1,165 @@
+<?php
+
+namespace Symfony\Component\Security\Http\RememberMe;
+
+use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
+use Symfony\Component\HttpFoundation\Cookie;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\CookieTheftException;
+use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Concrete implementation of the RememberMeServicesInterface which needs
+ * an implementation of TokenProviderInterface for providing remember-me
+ * capabilities.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class PersistentTokenBasedRememberMeServices extends RememberMeServices
+{
+ protected $tokenProvider;
+
+ /**
+ * Sets the token provider
+ *
+ * @param TokenProviderInterface $tokenProvider
+ * @return void
+ */
+ public function setTokenProvider(TokenProviderInterface $tokenProvider)
+ {
+ $this->tokenProvider = $tokenProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function processAutoLoginCookie(array $cookieParts, Request $request)
+ {
+ if (count($cookieParts) !== 2) {
+ throw new AuthenticationException('The cookie is invalid.');
+ }
+
+ list($series, $tokenValue) = $cookieParts;
+ $persistentToken = $this->tokenProvider->loadTokenBySeries($series);
+
+ if ($persistentToken->getTokenValue() !== $tokenValue) {
+ $this->tokenProvider->deleteTokenBySeries($series);
+
+ throw new CookieTheftException('This token was already used. The account is possibly compromised.');
+ }
+
+ if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
+ throw new AuthenticationException('The cookie has expired.');
+ }
+
+ $user = $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername());
+ $authenticationToken = new RememberMeToken($user, $this->providerKey, $this->key);
+ $authenticationToken->setPersistentToken($persistentToken);
+
+ return $authenticationToken;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
+ {
+ if ($token instanceof RememberMeToken) {
+ if (null === $persistentToken = $token->getPersistentToken()) {
+ throw new \RuntimeException('RememberMeToken must contain a PersistentTokenInterface implementation when used as login.');
+ }
+
+ $series = $persistentToken->getSeries();
+ $tokenValue = $this->generateRandomValue();
+
+ $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
+ } else {
+ $series = $this->generateRandomValue();
+ $tokenValue = $this->generateRandomValue();
+
+ $this->tokenProvider->createNewToken(
+ new PersistentToken(
+ get_class($user = $token->getUser()),
+ $user->getUsername(),
+ $series,
+ $tokenValue,
+ new \DateTime()
+ )
+ );
+ }
+
+ $response->headers->setCookie(
+ new Cookie(
+ $this->options['name'],
+ $this->generateCookieValue($series, $tokenValue),
+ time() + $this->options['lifetime'],
+ $this->options['path'],
+ $this->options['domain'],
+ $this->options['secure'],
+ $this->options['httponly']
+ )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function logout(Request $request, Response $response, TokenInterface $token)
+ {
+ parent::logout($request, $response, $token);
+
+ if (null !== ($cookie = $request->cookies->get($this->options['name']))
+ && count($parts = $this->decodeCookie($cookie)) === 2
+ ) {
+ list($series, $tokenValue) = $parts;
+ $this->tokenProvider->deleteTokenBySeries($series);
+ }
+ }
+
+ /**
+ * Generates the value for the cookie
+ *
+ * @param string $series
+ * @param string $tokenValue
+ * @return string
+ */
+ protected function generateCookieValue($series, $tokenValue)
+ {
+ return $this->encodeCookie(array($series, $tokenValue));
+ }
+
+ /**
+ * Generates a cryptographically strong random value
+ *
+ * @return string
+ */
+ protected function generateRandomValue()
+ {
+ if (function_exists('openssl_random_pseudo_bytes')) {
+ $bytes = openssl_random_pseudo_bytes(32, $strong);
+
+ if (true === $strong && false !== $bytes) {
+ return base64_encode($bytes);
+ }
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->warn('Could not produce a cryptographically strong random value. Please install/update the OpenSSL extension.');
+ }
+
+ return base64_encode(hash('sha256', uniqid(mt_rand(), true), true));
+ }
+}
diff --git a/Http/RememberMe/RememberMeServices.php b/Http/RememberMe/RememberMeServices.php
new file mode 100644
index 0000000..8b837df
--- /dev/null
+++ b/Http/RememberMe/RememberMeServices.php
@@ -0,0 +1,250 @@
+<?php
+
+namespace Symfony\Component\Security\Http\RememberMe;
+
+use Symfony\Component\Security\Core\User\AccountInterface;
+use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Base class implementing the RememberMeServicesInterface
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+abstract class RememberMeServices implements RememberMeServicesInterface, LogoutHandlerInterface
+{
+ const COOKIE_DELIMITER = ':';
+
+ protected $userProviders;
+ protected $options;
+ protected $logger;
+ protected $key;
+ protected $providerKey;
+
+ /**
+ * Constructor
+ *
+ * @param array $userProviders
+ * @param array $options
+ * @param LoggerInterface $logger
+ */
+ public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null)
+ {
+ if (empty($key)) {
+ throw new \InvalidArgumentException('$key must not be empty.');
+ }
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+ if (0 === count($userProviders)) {
+ throw new \InvalidArgumentException('You must provide at least one user provider.');
+ }
+
+ $this->userProviders = $userProviders;
+ $this->key = $key;
+ $this->providerKey = $providerKey;
+ $this->options = $options;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Implementation of RememberMeServicesInterface. Detects whether a remember-me
+ * cookie was set, decodes it, and hands it to subclasses for further processing.
+ *
+ * @param Request $request
+ * @return TokenInterface
+ */
+ public function autoLogin(Request $request)
+ {
+ if (null === $cookie = $request->cookies->get($this->options['name'])) {
+ return;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Remember-me cookie detected.');
+ }
+
+ $cookieParts = $this->decodeCookie($cookie);
+ $token = $this->processAutoLoginCookie($cookieParts, $request);
+
+ if (!$token instanceof TokenInterface) {
+ throw new \RuntimeException('processAutoLoginCookie() must return a TokenInterface implementation.');
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Remember-me cookie accepted.');
+ }
+
+ return $token;
+ }
+
+ /**
+ * Implementation for LogoutHandlerInterface. Deletes the cookie.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token
+ * @return void
+ */
+ public function logout(Request $request, Response $response, TokenInterface $token)
+ {
+ $this->cancelCookie($response);
+ }
+
+ /**
+ * Implementation for RememberMeServicesInterface. Deletes the cookie when
+ * an attempted authentication fails.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @return void
+ */
+ public function loginFail(Request $request, Response $response)
+ {
+ $this->cancelCookie($response);
+ }
+
+ /**
+ * Implementation for RememberMeServicesInterface. This is called when an
+ * authentication is successful.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token The token that resulted in a successful authentication
+ * @return void
+ */
+ public function loginSuccess(Request $request, Response $response, TokenInterface $token)
+ {
+ if (!$token instanceof RememberMeToken) {
+ if (!$token->getUser() instanceof AccountInterface) {
+ if (null !== $this->logger) {
+ $this->logger->debug('Remember-me ignores token since it does not contain an AccountInterface implementation.');
+ }
+
+ return;
+ }
+
+ if (!$this->isRememberMeRequested($request)) {
+ if (null !== $this->logger) {
+ $this->logger->debug('Remember-me was not requested.');
+ }
+
+ return;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Remember-me was requested; setting cookie.');
+ }
+ } else if (null !== $this->logger) {
+ $this->logger->debug('Re-newing remember-me token; setting cookie.');
+ }
+
+ $this->onLoginSuccess($request, $response, $token);
+ }
+
+ /**
+ * Subclasses should validate the cookie and do any additional processing
+ * that is required. This is called from autoLogin().
+ *
+ * @param array $cookieParts
+ * @param Request $request
+ * @return TokenInterface
+ */
+ abstract protected function processAutoLoginCookie(array $cookieParts, Request $request);
+
+ /**
+ * This is called after a user has been logged in successfully, and has
+ * requested remember-me capabilities. The implementation usually sets a
+ * cookie and possibly stores a persistent record of it.
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param TokenInterface $token
+ * @return void
+ */
+ abstract protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token);
+
+ protected function getUserProvider($class)
+ {
+ foreach ($this->userProviders as $provider) {
+ if ($provider->supportsClass($class)) {
+ return $provider;
+ }
+ }
+
+ throw new \RuntimeException(sprintf('There is no user provider that supports class "%s".', $class));
+ }
+
+ /**
+ * Decodes the raw cookie value
+ *
+ * @param string $rawCookie
+ * @return array
+ */
+ protected function decodeCookie($rawCookie)
+ {
+ return explode(self::COOKIE_DELIMITER, base64_decode($rawCookie));
+ }
+
+ /**
+ * Encodes the cookie parts
+ *
+ * @param array $cookieParts
+ * @return string
+ */
+ protected function encodeCookie(array $cookieParts)
+ {
+ return base64_encode(implode(self::COOKIE_DELIMITER, $cookieParts));
+ }
+
+ /**
+ * Deletes the remember-me cookie
+ *
+ * @param Response $response
+ * @return void
+ */
+ protected function cancelCookie(Response $response)
+ {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Clearing remember-me cookie "%s"', $this->options['name']));
+ }
+
+ $response->headers->clearCookie($this->options['name'], $this->options['path'], $this->options['domain']);
+ }
+
+ /**
+ * Checks whether remember-me capabilities where requested
+ *
+ * @param Request $request
+ * @return Boolean
+ */
+ protected function isRememberMeRequested(Request $request)
+ {
+ if (true === $this->options['always_remember_me']) {
+ return true;
+ }
+
+ $parameter = $request->request->get($this->options['remember_me_parameter']);
+
+ if ($parameter === null && null !== $this->logger) {
+ $this->logger->debug(sprintf('Did not send remember-me cookie (remember-me parameter "%s" was not sent).', $this->options['remember_me_parameter']));
+ }
+
+ return $parameter === 'true' || $parameter === 'on' || $parameter === '1' || $parameter === 'yes';
+ }
+}
diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php
new file mode 100644
index 0000000..0fcf99d
--- /dev/null
+++ b/Http/RememberMe/RememberMeServicesInterface.php
@@ -0,0 +1,66 @@
+<?php
+namespace Symfony\Component\Security\Http\RememberMe;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Interface that needs to be implemented by classes which provide remember-me
+ * capabilities.
+ *
+ * We provide two implementations out-of-the-box:
+ * - TokenBasedRememberMeServices (does not require a TokenProvider)
+ * - PersistentTokenBasedRememberMeServices (requires a TokenProvider)
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface RememberMeServicesInterface
+{
+ /**
+ * This method will be called whenever the SecurityContext does not contain
+ * an TokenInterface object and the framework wishes to provide an implementation
+ * with an opportunity to authenticate the request using remember-me capabilities.
+ *
+ * No attempt whatsoever is made to determine whether the browser has requested
+ * remember-me services or presented a valid cookie. Any and all such determinations
+ * are left to the implementation of this method.
+ *
+ * If a browser has presented an unauthorised cookie for whatever reason,
+ * make sure to throw an AuthenticationException as this will consequentially
+ * result in a call to loginFail() and therefore an invalidation of the cookie.
+ *
+ * @param Request $request
+ * @return TokenInterface
+ */
+ function autoLogin(Request $request);
+
+ /**
+ * Called whenever an authentication attempt was made, but the credentials
+ * supplied by the user were missing or otherwise invalid.
+ *
+ * This method needs to take care of invalidating the cookie.
+ */
+ function loginFail(Request $request, Response $response);
+
+ /**
+ * Called whenever authentication attempt is successful (e.g. a form login).
+ *
+ * An implementation may always set a remember-me cookie in the Response,
+ * although this is not recommended.
+ *
+ * Instead, implementations should typically look for a request parameter
+ * (such as a HTTP POST parameter) that indicates the browser has explicitly
+ * requested for the authentication to be remembered.
+ */
+ function loginSuccess(Request $request, Response $response, TokenInterface $token);
+} \ No newline at end of file
diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php
new file mode 100644
index 0000000..da5479d
--- /dev/null
+++ b/Http/RememberMe/TokenBasedRememberMeServices.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace Symfony\Component\Security\Http\RememberMe;
+
+use Symfony\Component\HttpFoundation\Cookie;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\User\AccountInterface;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Concrete implementation of the RememberMeServicesInterface providing
+ * remember-me capabilities without requiring a TokenProvider.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class TokenBasedRememberMeServices extends RememberMeServices
+{
+ /**
+ * {@inheritDoc}
+ */
+ protected function processAutoLoginCookie(array $cookieParts, Request $request)
+ {
+ if (count($cookieParts) !== 4) {
+ throw new AuthenticationException('The cookie is invalid.');
+ }
+
+ list($class, $username, $expires, $hash) = $cookieParts;
+ if (false === $username = base64_decode($username, true)) {
+ throw new AuthenticationException('$username contains a character from outside the base64 alphabet.');
+ }
+ try {
+ $user = $this->getUserProvider($class)->loadUserByUsername($username);
+ } catch (\Exception $ex) {
+ if (!$ex instanceof AuthenticationException) {
+ $ex = new AuthenticationException($ex->getMessage(), null, $ex->getCode(), $ex);
+ }
+
+ throw $ex;
+ }
+
+ if (!$user instanceof AccountInterface) {
+ throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of AccountInterface, but returned "%s".', get_class($user)));
+ }
+
+ if (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
+ throw new AuthenticationException('The cookie\'s hash is invalid.');
+ }
+
+ if ($expires < time()) {
+ throw new AuthenticationException('The cookie has expired.');
+ }
+
+ return new RememberMeToken($user, $this->providerKey, $this->key);
+ }
+
+ /**
+ * Compares two hashes using a constant-time algorithm to avoid (remote)
+ * timing attacks.
+ *
+ * This is the same implementation as used in the BasePasswordEncoder.
+ *
+ * @param string $hash1 The first hash
+ * @param string $hash2 The second hash
+ *
+ * @return Boolean true if the two hashes are the same, false otherwise
+ */
+ protected function compareHashes($hash1, $hash2)
+ {
+ if (strlen($hash1) !== $c = strlen($hash2)) {
+ return false;
+ }
+
+ $result = 0;
+ for ($i = 0; $i < $c; $i++) {
+ $result |= ord($hash1[$i]) ^ ord($hash2[$i]);
+ }
+
+ return 0 === $result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
+ {
+ if ($token instanceof RememberMeToken) {
+ return;
+ }
+
+ $user = $token->getUser();
+ $expires = time() + $this->options['lifetime'];
+ $value = $this->generateCookieValue(get_class($user), $user->getUsername(), $expires, $user->getPassword());
+
+ $response->headers->setCookie(
+ new Cookie(
+ $this->options['name'],
+ $value,
+ $expires,
+ $this->options['path'],
+ $this->options['domain'],
+ $this->options['secure'],
+ $this->options['httponly']
+ )
+ );
+ }
+
+ /**
+ * Generates the cookie value
+ *
+ * @param strign $class
+ * @param string $username The username
+ * @param integer $expires The unixtime when the cookie expires
+ * @param string $password The encoded password
+ * @throws \RuntimeException if username contains invalid chars
+ * @return string
+ */
+ protected function generateCookieValue($class, $username, $expires, $password)
+ {
+ return $this->encodeCookie(array(
+ $class,
+ base64_encode($username),
+ $expires,
+ $this->generateCookieHash($class, $username, $expires, $password)
+ ));
+ }
+
+ /**
+ * Generates a hash for the cookie to ensure it is not being tempered with
+ *
+ * @param string $class
+ * @param string $username The username
+ * @param integer $expires The unixtime when the cookie expires
+ * @param string $password The encoded password
+ * @throws \RuntimeException when the private key is empty
+ * @return string
+ */
+ protected function generateCookieHash($class, $username, $expires, $password)
+ {
+ return hash('sha256', $class.$username.$expires.$password.$this->key);
+ }
+}
diff --git a/Http/Session/SessionAuthenticationStrategy.php b/Http/Session/SessionAuthenticationStrategy.php
new file mode 100644
index 0000000..64f787f
--- /dev/null
+++ b/Http/Session/SessionAuthenticationStrategy.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Symfony\Component\Security\Http\Session;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInterface
+{
+ const NONE = 'none';
+ const MIGRATE = 'migrate';
+ const INVALIDATE = 'invalidate';
+
+ protected $strategy;
+
+ public function __construct($strategy)
+ {
+ $this->strategy = $strategy;
+ }
+
+ public function onAuthentication(Request $request, TokenInterface $token)
+ {
+ switch ($this->strategy) {
+ case self::NONE:
+ return;
+
+ case self::MIGRATE:
+ $request->getSession()->migrate();
+ return;
+
+ case self::INVALIDATE:
+ $request->getSession()->invalidate();
+ return;
+
+ default:
+ throw new \RuntimeException(sprintf('Invalid session authentication strategy "%s"', $this->strategy));
+ }
+ }
+} \ No newline at end of file
diff --git a/Http/Session/SessionAuthenticationStrategyInterface.php b/Http/Session/SessionAuthenticationStrategyInterface.php
new file mode 100644
index 0000000..c2d95c3
--- /dev/null
+++ b/Http/Session/SessionAuthenticationStrategyInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Symfony\Component\Security\Http\Session;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+interface SessionAuthenticationStrategyInterface
+{
+ function onAuthentication(Request $request, TokenInterface $token);
+} \ No newline at end of file