Skip to content

Commit

Permalink
Add a LDIF parser service. Allow tagging URL loaders to it.
Browse files Browse the repository at this point in the history
  • Loading branch information
ChadSikorra committed Sep 3, 2016
1 parent 4884cce commit ae604a2
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 1 deletion.
52 changes: 52 additions & 0 deletions DependencyInjection/Compiler/LdifUrlLoaderPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* This file is part of the LdapToolsBundle package.
*
* (c) Chad Sikorra <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Add any services tagged as a LDIF URL loader to the LDIF parser service.
*
* @author Chad Sikorra <[email protected]>
*/
class LdifUrlLoaderPass implements CompilerPassInterface
{
/**
* The LDIF URL loader tag name.
*/
const LDIF_URL_LOADER_TAG = 'ldap_tools.ldif_url_loader';

/**
* The LDIF parser service name.
*/
const LDIF_PARSER = 'ldap_tools.ldif_parser';

/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$urlLoaders = $container->findTaggedServiceIds(self::LDIF_URL_LOADER_TAG);
if (empty($urlLoaders)) {
return;
}
$parser = $container->findDefinition(self::LDIF_PARSER);

foreach ($urlLoaders as $id => $loader) {
if (!isset($loader[0]['type'])) {
throw new \InvalidArgumentException(sprintf('Service "%s" must define the "type" attribute on "%s" tags.', $id, self::LDIF_URL_LOADER_TAG));
}
$parser->addMethodCall('setUrlLoader', [$loader[0]['type'], new Reference($id)]);
}
}
}
2 changes: 2 additions & 0 deletions LdapToolsBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace LdapTools\Bundle\LdapToolsBundle;

use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\EventRegisterPass;
use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\LdifUrlLoaderPass;
use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Security\Factory\LdapFormLoginFactory;
use LdapTools\Bundle\LdapToolsBundle\Doctrine\Type\LdapObjectCollectionType;
use LdapTools\Bundle\LdapToolsBundle\Doctrine\Type\LdapObjectType;
Expand Down Expand Up @@ -57,5 +58,6 @@ public function build(ContainerBuilder $container)
$extension = $container->getExtension('security');
$extension->addSecurityListenerFactory(new LdapFormLoginFactory());
$container->addCompilerPass(new EventRegisterPass());
$container->addCompilerPass(new LdifUrlLoaderPass());
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ class DefaultController extends Controller
* [LDAP Authentication Provider](/Resources/doc/LDAP-Authentication-Provider.md)
* [LDAP Object Form Type](/Resources/doc/LDAP-Object-Form-Type.md)
* [LDAP Events](/Resources/doc/LDAP-Events.md)
* [LDIF Parser URL Loaders](/Resources/doc/LDIF-Parser-URL-Loaders.md)
3 changes: 3 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<parameters>
<parameter key="ldap_tools.ldap_manager.class">LdapTools\LdapManager</parameter>
<parameter key="ldap_tools.configuration.class">LdapTools\Configuration</parameter>
<parameter key="ldap_tools.ldif.parser.class">LdapTools\Ldif\LdifParser</parameter>
<parameter key="ldap_tools.event_dispatcher.class">LdapTools\Event\SymfonyEventDispatcher</parameter>
<parameter key="ldap_tools.security.firewall.ldap_form_login_listener.class">LdapTools\Bundle\LdapToolsBundle\Security\Firewall\LdapFormLoginListener</parameter>
<parameter key="ldap_tools.security.user.ldap_user_provider.class">LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUserProvider</parameter>
Expand Down Expand Up @@ -53,6 +54,8 @@

<service id="ldap_tools.security.user.ldap_user_checker" class="%ldap_tools.security.user.ldap_user_checker.class%" />

<service id="ldap_tools.ldif_parser" class="%ldap_tools.ldif.parser.class%" />

<service id="ldap_tools.security.firewall.ldap_form_login_listener"
class="%ldap_tools.security.firewall.ldap_form_login_listener.class%"
parent="security.authentication.listener.abstract"
Expand Down
92 changes: 92 additions & 0 deletions Resources/doc/LDIF-Parser-URL-Loaders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
LDIF Parser URL Loaders
================

The LdapTools library includes a [LDIF Parser](https://github.com/ldaptools/ldaptools/blob/master/docs/en/tutorials/LDIF-Files.md) capable of loading LDIF values from a URL (such as `http://` or `file://`).
By default it only includes support for a limited number of URL types. If you have your own URL type you want to use in
a LDIF file to load data then you need to create a [LDIF URL Loader](https://github.com/ldaptools/ldaptools/blob/master/docs/en/tutorials/LDIF-Files.md#ldif-url-loaders) which is a class that implements `LdapTools\Ldif\UrlLoader\UrlLoaderInterface`.
Then you need to add an instance of that URL Loader to the LDIF Parser class via `setUrlLoader($type, $loader)`.

The above process is made easy in this bundle by first create the LDIF URL Loader, registering it as a service, then simply
tagging the service with the `ldap_tools.ldif_url_loader` tag and a `type` property on the tag that defines the type of
URL it is (ie. `https`, `file`, etc).

## Create the LDIF URL Loader

```php
namespace AppBundle\LdifUrlLoader;

use LdapTools\Ldif\LdifUrlLoader\UrlLoaderInterface;

class LdifHttpsLoader implements UrlLoaderInterface
{
/**
* {@inheritdoc}
*/
public function load($url)
{
// Custom logic for your URL loading process here...

// Return the resulting data...
return $data;
}
}
```

## Define the LDIF URL Loader as a Service

```yaml
<?xml version="1.0" ?>
<!-- ... -->
<services>
<!-- ... -->

<service id="app.ldif_url_loader" class="AppBundle\LdifUrlLoader\LdifHttpsLoader" >
<tag name="ldap_tools.ldif_url_loader" type="https"/>
</service>

<!-- ... -->
</services>
</container>
```

Now in your LDIF files your URL loader will be used when parsing files that consume data from the URL.

Assume a LDIF file with an entry like:

```
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Barbara Jensen
sn: Jensen
uid: bjensen
telephonenumber: +1 408 555 1212
description:< https://example.local/users/bjensen.html
```

The `description` at the bottom will be loaded from the URL Loader, such as in a controller:

```php

class DefaultController extends Controller
{
public function indexAction()
{
try {
# Use the LDIF parser from the service which will have the URL loader set...
$ldif = $this->get('ldap_tools.ldif_parser')->parse(file_get_contents('/path/to/ldif.txt'));
} catch (LdifParserException $e) {
echo "Error Parsing LDIF: ".$e->getMessage();
}

// Iterate through the operations parsed from the LDIF file...
foreach ($ldif->toOperations() as $operation) {
// Load them into LDAP if you want...
$this->get('ldap_tools.ldap_manager')->getConnection()->execute($operation);
}

# ...
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of the LdapToolsBundle package.
*
* (c) Chad Sikorra <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace spec\LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler;

use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\LdifUrlLoaderPass;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

class LdifUrlLoaderPassSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\LdifUrlLoaderPass');
}

function it_should_process_tagged_services_when_there_are_none_found(ContainerBuilder $container)
{
$container->findTaggedServiceIds(LdifUrlLoaderPass::LDIF_URL_LOADER_TAG)->willReturn([]);
$container->findDefinition(Argument::any())->shouldNotBeCalled();

$this->process($container);
}

function it_should_process_tagged_services_when_they_exist(ContainerBuilder $container, Definition $definition)
{
$id = 'foo.ldif_url_loader';
$container->findTaggedServiceIds(LdifUrlLoaderPass::LDIF_URL_LOADER_TAG)->willReturn(
[$id => [['type' => 'foo']]]
);
$container->findDefinition(LdifUrlLoaderPass::LDIF_PARSER)->shouldBeCalled()->willReturn($definition);
$definition->addMethodCall('setUrlLoader', ['foo', new Reference($id)])->shouldBeCalled();

$this->process($container);
}

function it_should_require_the_type_property_for_the_tag(ContainerBuilder $container, Definition $definition)
{
$id = 'foo.ldif_url_loader';
$container->findTaggedServiceIds(LdifUrlLoaderPass::LDIF_URL_LOADER_TAG)->willReturn([$id => [[]]]);
$container->findDefinition(LdifUrlLoaderPass::LDIF_PARSER)->shouldBeCalled()->willReturn($definition);

$this->shouldThrow(new \InvalidArgumentException('Service "foo.ldif_url_loader" must define the "type" attribute on "ldap_tools.ldif_url_loader" tags.'))->duringProcess($container);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ function it_should_load_the_configuration()
$this->container->setDefinition('ldap_tools.form.type.ldap_object', Argument::type('Symfony\Component\DependencyInjection\Definition'))->shouldBeCalled();
$this->container->setDefinition('ldap_tools.doctrine.event_listener.ldap_object', Argument::type('Symfony\Component\DependencyInjection\Definition'))->shouldBeCalled();
$this->container->setDefinition('ldap_tools.security.ldap_guard_authenticator', Argument::type('Symfony\Component\DependencyInjection\Definition'))->shouldBeCalled();
$this->container->setDefinition('ldap_tools.ldif_parser', Argument::type('Symfony\Component\DependencyInjection\Definition'))->shouldBeCalled();

// Sets these by default when a domain is defined...
$this->cacheWarmer->addTag("kernel.cache_warmer")->shouldBeCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

use Doctrine\DBAL\Types\Type;
use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\EventRegisterPass;
use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Compiler\LdifUrlLoaderPass;
use LdapTools\Bundle\LdapToolsBundle\DependencyInjection\Security\Factory\LdapFormLoginFactory;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class LdapToolsBundleSpec extends ObjectBehavior
{
Expand All @@ -32,6 +32,7 @@ function it_should_add_the_security_listener_factory_and_compiler_pass_when_call
$extension->addSecurityListenerFactory(new LdapFormLoginFactory())->shouldBeCalled();
$container->getExtension('security')->willReturn($extension);
$container->addCompilerPass(new EventRegisterPass())->shouldBeCalled();
$container->addCompilerPass(new LdifUrlLoaderPass())->shouldBeCalled();

$this->build($container);
}
Expand Down

0 comments on commit ae604a2

Please sign in to comment.