Skip to content

Instantly share code, notes, and snippets.

@umpirsky
Created May 31, 2011 11:33
Show Gist options
  • Save umpirsky/1000349 to your computer and use it in GitHub Desktop.
Save umpirsky/1000349 to your computer and use it in GitHub Desktop.
security.authentication.listener.url:
class: Мз\Security\Http\Firewall\UrlAuthenticationListener
arguments: [@security.context, @security.authentication.manager, @security.authentication.session_strategy, 'secured_area', {login_path: '/not-auth', check_path: '/auth/customer', default_target_path: '/хоме'}]
tags:
- { name: monolog.logger, channel: security }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
users:
admin: { password: admin, roles: 'ROLE_ADMIN' }
access_control:
- { path: ^/, roles: ROLE_ADMIN }
factories:
UrlSecurityFactory: %kernel.root_dir%/../src/My/Resources/config/security_factories.xml
firewalls:
profiler:
pattern: ^/_profiler
security: false
wdt:
pattern: ^/_wdt
security: false
notauth:
pattern: ^/not-auth
security: false
secured_area:
pattern: ^/
security: true
url_login: ~
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="security.authentication.factory.url" class="My\Security\Factory\UrlLoginFactory">
<tag name="security.listener.factory" />
</service>
</services>
</container>
<?php
namespace My\Security\Factory;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\SecurityContextInterface;
class UrlAuthenticationListener extends AbstractAuthenticationListener
{
protected function attemptAuthentication(Request $request)
{
$username = 'admin';
$password = 'admin';
$request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}
<?php
namespace My\Security\Factory;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
/**
* UrlLoginFactory creates services for url login authentication.
*
* @author umpirsky
*/
class UrlLoginFactory extends AbstractFactory
{
/**
* @see Symfony\Bundle\FrameworkBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface::getPosition()
*/
public function getPosition()
{
return 'pre_auth';
}
/**
* @see Symfony\Bundle\FrameworkBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface::getKey()
*/
public function getKey()
{
return 'url-login';
}
protected function getListenerId()
{
return 'security.authentication.listener.url';
}
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication.provider.dao.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.dao'))
->replaceArgument(0, new Reference($userProviderId))
->replaceArgument(2, 'secured_area')
->addArgument($id)
;
return $provider;
}
protected function createListener($container, $id, $config, $userProvider)
{
$listenerId = $this->getListenerId();
$listener = new DefinitionDecorator($listenerId);
$listenerId .= '.'.$id;
$container->setDefinition($listenerId, $listener);
return $listenerId;
}
protected function createEntryPoint($container, $id, $config, $defaultEntryPointId)
{
return $defaultEntryPointId;
}
}
@stof
Copy link

stof commented May 31, 2011

The definition of the security.authentication.listener.url service is wrong. It does not correspond to the argument you need to pass to it (its constructor has some requirements).

@umpirsky
Copy link
Author

I fixed createListener() method, and now I get "A Token was not found in the SecurityContext. ".

@stof
Copy link

stof commented May 31, 2011

This probably means that your provider is wrong.

@umpirsky
Copy link
Author

I got in memmory provider defined in https://gist.github.com/1000349#file_security.yml.

@stof
Copy link

stof commented May 31, 2011

Is your URL behind a firewall ?

@umpirsky
Copy link
Author

Yes. But maybe in https://gist.github.com/1000349#file_url_login_factory.php createAuthProvider() is not ok. I don't have some good example on how this part should look like, and I'm not sure what security.authentication.provider.dao is. But I would like to test this with in memmory provider and migrate to entity provider later.

@umpirsky
Copy link
Author

Fixed createAuthProvider(). Now I get Fatal error: Call to undefined method Symfony\Component\Security\Core\User\InMemoryUserProvider::supports() in Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php on line 56

@stof
Copy link

stof commented May 31, 2011

You messed the authentication provider and the user provider. The AuthenticationProviderManager should receive some authentication providers. InMemoryUserProvider is a user provider (as stated in its name)

@umpirsky
Copy link
Author

Ugh, you are right. Thanks. It's so hard when there is no documentation. I'm trying to implement simple authentication via url. Can you suggest which authentication provider should I use?

@stof
Copy link

stof commented May 31, 2011

I think the good choice is PreAuthenticatedAuthenticationProvider, as you are defining a pre_auth listener. check the X509Factory to see how it is done.

@umpirsky
Copy link
Author

i did that in createAuthProvider() but still getting "A Token was not found in the SecurityContext. " error.

@umpirsky
Copy link
Author

I came to an interesting result. After hours of debugging. I have chaged https://gist.github.com/1000349#file_cnofig.yml and find out that it works if I set 3rd argument of my listener to 'secured_area' value. Don't know why it compares to 'secured_area', but when I set that value, it always authenticates me as admin when I put 'admin' for username in https://gist.github.com/1000349#file_url_authentication_listener.php no mattter what I enter for credentials, it only check username. If I change username to something other then 'admin' it gives "A Token was not found in the SecurityContext." again. Also, the interesting thing is that after clearing the session it auto authenticates on all urls. Can you help put me on right way? I feel I'm close to the solution. Thanks.

@stof
Copy link

stof commented May 31, 2011

the point is that your listener always return array('admin', 'admin'). It does not check if the URL contains something.

@umpirsky
Copy link
Author

I know, I just want to simulate auth with hardcoded values. Thse hardcoded array('admin', 'admin') I will get from request ofc. I expected that it checks credentials for me. As you can see, I have in memmory user provider with user admin: { password: admin, roles: 'ROLE_ADMIN' }. so auth should fail if I hardcode array('admin', 'admin2'), but it authenticates in that case too. If I hardcode array('admin2', 'admin') it fails with "A Token was not found in the SecurityContext. " error. I wonder why that happens?

@umpirsky
Copy link
Author

Maybe I should extend my listener from AbstractAuthenticationListener instead AbstractPreAuthenticatedListener. But whenever I try that, I end up with damn "A Token was not found in the SecurityContext." :) It should more or less work like UsernamePasswordFormAuthenticationListener, but get username and password from GET instead from POST. Later I can add some sha1 with secret key.

@stof
Copy link

stof commented May 31, 2011

How are the username and password passed to the app ? can you give an example of url ?

@umpirsky
Copy link
Author

For now they are hardcoded in https://gist.github.com/1000349#file_url_authentication_listener.php. But they will be passed like /auth/username/admin/hash/foo via url. But I'm hardcoding for now to keep it simpler for testing. Passing user/pass is not the problem I'm trying to solve now. Problem is authentication itself.

With current listener implementation https://gist.github.com/1000349#file_url_authentication_listener.php with 'admin' username it is always authenticated, no matter what password (credentials) I enter. And it triggers authentication on all urls, but I guess that's how AbstractPreAuthenticatedListener works.

@umpirsky
Copy link
Author

If we ever solve this, I will write detailed instructions about implementing custom authentication system with Symfony2.

@umpirsky
Copy link
Author

umpirsky commented Jun 1, 2011

OK, I kind of sorted it all out. I switched to AbstractAuthenticationListener instead AbstractPreAuthenticatedListener. Added provider key and config to https://gist.github.com/1000349#file_cnofig.yml. And add some magic in createAuthProvider() method. Now it works.

The only thing that are not clear to me are is what is providerKey? I hardcoded it in createAuthProvider() and config.yml, but don't know what is it and how to use it?

Thanks.

@umpirsky
Copy link
Author

umpirsky commented Jun 1, 2011

Strange is that I don't get usual "Full authenticvation required to access this resource" when I'm unauthorised and go to some protected url, but get "A Token was not found in the SecurityContext.".

@kayue
Copy link

kayue commented Aug 7, 2011

Hi umpirsky, did you figure out how to solve this?

@umpirsky
Copy link
Author

@kayue Yes, but it was very hard work, and I suggest you to give up, you can make it on your own better. Maybe situation is now better since stable Symfony2 is released.

@kayue
Copy link

kayue commented Aug 16, 2011

@umpirsky:

I was trying to create a Wordpress Bridge (https://github.com/kayue/WordpressBundle).
I figured out the "A Token was not found in the SecurityContext." could be fixed if I add anonymous to my firewall.

Don't know are we talking about the same issue.

@umpirsky
Copy link
Author

@kayue I think not :)

@ecoad
Copy link

ecoad commented Nov 16, 2011

@kayue:

Thankyou! Add "anonymous" to firewall

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment