6

I am already loggedin to main domain. Say example.com (app developed in legacy kohana). I am trying to login to subdmain, say foo.bar.example.com .

foo.example.com is symfony app. Below is my configuration. Dev too bar displays "anonymous" user. It doesn't loggin user from session id in cookie.

security.yml

# To get started with security, check out the documentation:
# http://symfony.com/doc/current/book/security.html
security:

    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    providers:
        in_memory:
            memory: ~

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            anonymous: ~
            # activate different ways to authenticate

            # http_basic: ~
            # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: ~
            # http://symfony.com/doc/current/cookbook/security/form_login_setup.html

Config.yml

framework:
    #esi:             ~
    #translator:      { fallbacks: ["%locale%"] }
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    #serializer:      { enable_annotations: true }
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies:  %trusted_proxies%
    session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  'snc_redis.session.handler'
        name: 'MY_COOKIE_NAME'
        cookie_domain: '.example.com'
    fragments:       ~
    http_method_override: true
    request:
        formats:
            pdf: 'application/pdf'
            epub: 'application/epub+zip'


snc_redis:
    session:
        client: session
        prefix: ''
    clients:
        default:
            type: predis
            alias: default
            dsn: %redis_dsn%
            logging: false
            options:
#                profile: 2.6
                profile: 2.2
                connection_persistent: false
        slave:
            type: predis
            alias: slave
            logging: false
            dsn: %redis_dsn_slave%

        session:
            type: predis
            alias: session
            dsn: %redis_dsn%

Do I need to have atleast one authentication provider configured ? or I need to write custom authentication provider something which works like remember me ?

Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener->handle

has

  if ($this->options['require_previous_session'] && !$request->hasPreviousSession()) {
                throw new SessionUnavailableException('Your session has timed out, or you have disabled cookies.');
            }

and Request has

public function hasPreviousSession()
{
    // the check for $this->session avoids malicious users trying to fake a session cookie with proper name
    return $this->hasSession() && $this->cookies->has($this->session->getName());
}
vishal
  • 3,993
  • 14
  • 59
  • 102
  • By default the session cookie is configured on the subdomain, in order to make that same cookie accessible make sure to check whether the SESSIONID cookie has the correct TLD domain. So, "example.com" instead of "sub.example.com". – Rvanlaak Sep 20 '16 at 12:27
  • I have set the domain correctly. but still no luck – vishal Sep 20 '16 at 13:25
  • Symfony will not use that `SESSIONID` automatically, you should create your own `Provider` that can match that session against the ones in the (shared) database. After that you can set the `UsernamePasswordToken` manually. – Rvanlaak Sep 20 '16 at 13:46
  • There must be default implementation which matches sessionId in cookie with session stored in file system. I have configured redis session handler, and mapped it to session.handler_id. Sorry couldnt understand why do we need to write custom provider. – vishal Sep 20 '16 at 13:55

1 Answers1

0

In the main domain and after login you can save the token into database and cookies and in the second app you should create a custom authentificator who can recover the token from navigator and fetch into data base. If it finds a match it will authentificate the user.

security:

# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-

    firewalls:
    # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            stateless: true
            provider: customProvider
            guard:
                authenticators:
                    - App\Security\TokenAuthenticator

src/Security/TokenAuthenticator.php

namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;

class TokenAuthenticator extends AbstractGuardAuthenticator
{
private $em;

public function __construct(EntityManagerInterface $em)
{
    $this->em = $em;
}

/**
 * Called on every request to decide if this authenticator should be
 * used for the request. Returning false will cause this authenticator
 * to be skipped.
 */
public function supports(Request $request)
{
    return true;
}

/**
 * Called on every request. Return whatever credentials you want to
 * be passed to getUser() as $credentials.
 */
public function getCredentials(Request $request)
{
    return [
        'token' => // recover token from cookies,
    ];
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
    $token = $credentials['token'];

    if (null === $token) {
        return;
    }

    // if a User object, checkCredentials() is called
    return $this->em->getRepository(User::class)
        ->findOneBy(['token' => $token]);
}

public function checkCredentials($credentials, UserInterface $user)
{
    // check credentials - e.g. make sure the password is valid
    // no credential check is needed in this case

    // return true to cause authentication success
    return true;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    // on success, let the request continue
    return null;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
    $data = [
        'message' => strtr($exception->getMessageKey(), $exception->getMessageData())

        // or to translate this message
        // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
    ];

    return new JsonResponse($data, Response::HTTP_FORBIDDEN);
}

/**
 * Called when authentication is needed, but it's not sent
 */
public function start(Request $request, AuthenticationException $authException = null)
{
    $data = [
        // you might translate this message
        'message' => 'Authentication Required'
    ];

    return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}

public function supportsRememberMe()
{
    return false;
}
}

I hope it solves your problem

Themer
  • 584
  • 4
  • 9