diff options
author | Johannes M. Schmitt <schmittjoh@gmail.com> | 2011-01-26 21:34:11 +0100 |
---|---|---|
committer | Fabien Potencier <fabien.potencier@gmail.com> | 2011-01-26 22:23:20 +0100 |
commit | bebc09870cb0a7720e2c6a8c5c74585e69e8bb24 (patch) | |
tree | 0c399647cdbe504be405017e7cc04c70c53482f2 | |
parent | c85f3d708d2c9b00d73ca1234ccfaf50336d94b1 (diff) | |
download | symfony-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.php | 2 | ||||
-rw-r--r-- | Acl/Domain/SecurityIdentityRetrievalStrategy.php | 12 | ||||
-rw-r--r-- | Acl/Domain/UserSecurityIdentity.php | 4 | ||||
-rw-r--r-- | Acl/Model/SecurityIdentityRetrievalStrategyInterface.php | 2 | ||||
-rw-r--r-- | Acl/Voter/AclVoter.php | 6 | ||||
-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.php | 49 | ||||
-rw-r--r-- | Http/Authentication/AuthenticationFailureHandlerInterface.php | 11 | ||||
-rw-r--r-- | Http/Authentication/AuthenticationSuccessHandlerInterface.php | 12 | ||||
-rw-r--r-- | Http/EntryPoint/BasicAuthenticationEntryPoint.php | 41 | ||||
-rw-r--r-- | Http/EntryPoint/DigestAuthenticationEntryPoint.php | 74 | ||||
-rw-r--r-- | Http/EntryPoint/FormAuthenticationEntryPoint.php | 56 | ||||
-rw-r--r-- | Http/EntryPoint/RetryAuthenticationEntryPoint.php | 60 | ||||
-rw-r--r-- | Http/ExceptionTranslation/AccessDeniedHandlerInterface.php | 27 | ||||
-rw-r--r-- | Http/Firewall.php | 95 | ||||
-rw-r--r-- | Http/Firewall/AbstractAuthenticationListener.php | 285 | ||||
-rw-r--r-- | Http/Firewall/AccessListener.php | 92 | ||||
-rw-r--r-- | Http/Firewall/AnonymousAuthenticationListener.php | 77 | ||||
-rw-r--r-- | Http/Firewall/BasicAuthenticationListener.php | 115 | ||||
-rw-r--r-- | Http/Firewall/ChannelListener.php | 88 | ||||
-rw-r--r-- | Http/Firewall/ContextListener.php | 175 | ||||
-rw-r--r-- | Http/Firewall/DigestAuthenticationListener.php | 239 | ||||
-rw-r--r-- | Http/Firewall/ExceptionListener.php | 170 | ||||
-rw-r--r-- | Http/Firewall/ListenerInterface.php | 42 | ||||
-rw-r--r-- | Http/Firewall/LogoutListener.php | 105 | ||||
-rw-r--r-- | Http/Firewall/PreAuthenticatedListener.php | 116 | ||||
-rw-r--r-- | Http/Firewall/RememberMeListener.php | 148 | ||||
-rw-r--r-- | Http/Firewall/SwitchUserListener.php | 184 | ||||
-rw-r--r-- | Http/Firewall/UsernamePasswordFormAuthenticationListener.php | 64 | ||||
-rw-r--r-- | Http/Firewall/X509AuthenticationListener.php | 46 | ||||
-rw-r--r-- | Http/FirewallMap.php | 43 | ||||
-rw-r--r-- | Http/FirewallMapInterface.php | 28 | ||||
-rw-r--r-- | Http/Logout/CookieClearingLogoutHandler.php | 59 | ||||
-rw-r--r-- | Http/Logout/LogoutHandlerInterface.php | 36 | ||||
-rw-r--r-- | Http/Logout/SessionLogoutHandler.php | 37 | ||||
-rw-r--r-- | Http/RememberMe/PersistentTokenBasedRememberMeServices.php | 165 | ||||
-rw-r--r-- | Http/RememberMe/RememberMeServices.php | 250 | ||||
-rw-r--r-- | Http/RememberMe/RememberMeServicesInterface.php | 66 | ||||
-rw-r--r-- | Http/RememberMe/TokenBasedRememberMeServices.php | 153 | ||||
-rw-r--r-- | Http/Session/SessionAuthenticationStrategy.php | 39 | ||||
-rw-r--r-- | Http/Session/SessionAuthenticationStrategyInterface.php | 11 |
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 |