Skip to content

Instantly share code, notes, and snippets.

@Pierstoval
Last active February 4, 2020 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pierstoval/1e29a9badab1cba03e45a306aa658c83 to your computer and use it in GitHub Desktop.
Save Pierstoval/1e29a9badab1cba03e45a306aa658c83 to your computer and use it in GitHub Desktop.
(for stackoverflow)
<?php
/**
* This file is part of the corahn_rin package.
*
* (c) Alexandre Rock Ancelet <alex@orbitale.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace User\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use User\Entity\User;
use User\Repository\UserRepository;
final class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
public const USERNAME_OR_EMAIL_FORM_FIELD = '_username_or_email';
public const PASSWORD_FORM_FIELD = '_password';
private const PROVIDER_KEY = 'main'; // Firewall name
private const LOGIN_ROUTE = 'user_login';
private const NO_REFERER_ROUTES = [
self::LOGIN_ROUTE,
'user_login_check',
'user_register',
'user_logout',
'user_check_email',
'user_registration_confirm',
'user_registration_confirmed',
'user_resetting_request',
'user_resetting_send_email',
'user_resetting_check_email',
'user_resetting_reset',
'user_change_password',
];
private $httpKernel;
private $httpUtils;
private $router;
private $encoder;
private $defaultLocale;
public function __construct(
HttpKernelInterface $kernel,
HttpUtils $httpUtils,
RouterInterface $router,
UserPasswordEncoderInterface $encoder,
string $defaultLocale
) {
$this->httpKernel = $kernel;
$this->httpUtils = $httpUtils;
$this->router = $router;
$this->encoder = $encoder;
$this->defaultLocale = $defaultLocale;
}
/**
* {@inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null)
{
if (\in_array($request->attributes->get('_route'), static::NO_REFERER_ROUTES, true)) {
$this->removeTargetPath($request->getSession(), static::PROVIDER_KEY);
} elseif (!$this->getTargetPath($request->getSession(), static::PROVIDER_KEY)) {
$this->saveTargetPath($request->getSession(), static::PROVIDER_KEY, $request->getUri());
}
// Forward the request to the login controller, to avoid too many redirections.
$subRequest = $this->httpUtils->createRequest($request, $this->getLoginUrl());
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
if (200 === $response->getStatusCode()) {
$response->setStatusCode(401);
}
return $response;
}
/**
* {@inheritdoc}
*/
public function supports(Request $request)
{
return
$request->isMethod('POST')
&& $request->request->has(self::USERNAME_OR_EMAIL_FORM_FIELD)
&& $request->request->has(self::PASSWORD_FORM_FIELD)
&& $request->getPathInfo() === $this->router->generate('user_login_check')
;
}
/**
* {@inheritdoc}
*/
protected function getLoginUrl()
{
return $this->router->generate(static::LOGIN_ROUTE);
}
/**
* {@inheritdoc}
*/
public function getCredentials(Request $request)
{
$usernameOrEmail = $request->request->get(self::USERNAME_OR_EMAIL_FORM_FIELD);
$request->getSession()->set(Security::LAST_USERNAME, $usernameOrEmail);
$password = $request->request->get(self::PASSWORD_FORM_FIELD);
return UsernamePasswordCredentials::create(
$usernameOrEmail,
$password
);
}
/**
* {@inheritdoc}
*
* @param UsernamePasswordCredentials $credentials
* @param UserRepository $userProvider
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
$user = $userProvider->loadUserByUsername($credentials->getUsernameOrEmail());
if (!$user) {
throw new AuthenticationException('security.bad_credentials');
}
if ($user && !$user->isEmailConfirmed()) {
throw new AuthenticationException('security.email_not_confirmed');
}
return $user;
}
/**
* {@inheritdoc}
*
* @param UsernamePasswordCredentials $credentials
* @param UserInterface|User $user
*/
public function checkCredentials($credentials, UserInterface $user)
{
if (!$this->encoder->isPasswordValid($user, $credentials->getPassword())) {
throw new BadCredentialsException('security.bad_credentials');
}
return true;
}
/**
* {@inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$session = $request->getSession();
$targetPath = $this->getTargetPath($session, $providerKey);
if (!$targetPath) {
$targetPath = \rtrim($this->router->generate('root', ['_locale' => $request->getLocale() ?: $this->defaultLocale]), '/').'/';
}
// Make sure username is not stored for next login
$session->remove(Security::LAST_USERNAME);
$this->removeTargetPath($session, $providerKey);
return new RedirectResponse($targetPath);
}
}
framework:
#esi: ~
#fragments: ~
secret: '%env(APP_SECRET)%'
csrf_protection: ~
http_method_override: true
form: ~
validation: { enable_annotations: true }
php_errors:
log: true
assets:
version: '%version_code%'
version_format: '%%s?assetv=%%s'
trusted_hosts:
- '%env(ESTEREN_DOMAIN)%$'
- '%env(AGATE_DOMAIN)%$'
- '%env(DRAGONS_DOMAIN)%$'
- '%env(VERMINE_DOMAIN)%$'
session:
# http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
handler_id: session.handler.native_file
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
enabled: true
name: AgateSessionCookie
gc_maxlifetime: 864000
cookie_httponly: true
cookie_lifetime: 86400
# To add when SF 4.2 releases
#cookie_samesite: lax
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/security.html
security:
# http://symfony.com/doc/current/security.html#encoding-the-user-s-password
encoders:
Symfony\Component\Security\Core\User\UserInterface: bcrypt
# http://symfony.com/doc/current/security.html#hierarchical-roles
role_hierarchy:
# Anyone who is a backer from Kickstarter or Ulule.
ROLE_BACKER: ROLE_USER
# A user that can view the map is automatically a user.
ROLE_MAPS_VIEW: ROLE_USER
# Backers "Travels" reedition
ROLE_BACKER_TRAVELS:
- ROLE_BACKER
- ROLE_MAPS_VIEW
# Content managers (access to backend)
ROLE_MANAGER: ROLE_USER
# Maps
ROLE_ADMIN_MAPS: ROLE_MANAGER
# Character Generator
ROLE_ADMIN_GENERATOR: ROLE_MANAGER
# Translator
ROLE_ADMIN_TRANSLATOR: ROLE_MANAGER
# Admins
ROLE_ADMIN:
- ROLE_MANAGER
- ROLE_ADMIN_GENERATOR
- ROLE_ADMIN_MAPS
- ROLE_ADMIN_TRANSLATOR
ROLE_SUPER_ADMIN:
- ROLE_BACKER_TRAVELS
- ROLE_ADMIN
- ROLE_ALLOWED_TO_SWITCH
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
user_provider:
id: User\Repository\UserRepository
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: '^/(_(profiler|wdt)|css|images|img|fonts|map_tiles|uploads|components|bundles|js|(%locales_regex%)/js/translations)/'
security: false
# http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# http://symfony.com/doc/current/security/form_login_setup.html
main:
pattern: ^/
anonymous: ~
provider: user_provider
remember_me:
secret: '%env(APP_SECRET)%'
path: /
name: EsterenRememberMe
logout:
invalidate_session: false
path: user_logout
target: root
guard:
authenticators:
- User\Security\FormLoginAuthenticator
# with these settings you can restrict or allow access for different parts
# of your application based on roles, ip, host or methods
# http://symfony.com/doc/current/security.html#security-book-access-control-matching-options
access_control:
- { path: '^/(?:%locales_regex%)/login', role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: '^/(?:%locales_regex%)/register', role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: '^/(?:%locales_regex%)/resetting', role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: '^/(?:%locales_regex%)/profile', role: ROLE_USER }
- { path: '^/(?:%locales_regex%)/characters', role: ROLE_USER }
- { path: '^/(?:%locales_regex%)/map-.*$', host: '%esteren_domains.esterenmaps%', role: ROLE_MAPS_VIEW }
- { path: '^/', host: '%esteren_domains.backoffice%', role: ROLE_MANAGER }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment