vendor/bundles/JMS/SecurityExtraBundle/DependencyInjection/Compiler/SecureMethodInvocationsPass.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/bundles/JMS/SecurityExtraBundle/DependencyInjection/Compiler/SecureMethodInvocationsPass.php Sat Sep 24 15:40:41 2011 +0200
@@ -0,0 +1,193 @@
+<?php
+
+/*
+ * Copyright 2010 Johannes M. Schmitt <schmittjoh@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace JMS\SecurityExtraBundle\DependencyInjection\Compiler;
+
+use JMS\SecurityExtraBundle\Analysis\ServiceAnalyzer;
+use JMS\SecurityExtraBundle\Metadata\ServiceMetadata;
+use JMS\SecurityExtraBundle\Metadata\ClassMetadata;
+use JMS\SecurityExtraBundle\Generator\ProxyClassGenerator;
+use JMS\SecurityExtraBundle\Metadata\Driver\DriverChain;
+use \ReflectionClass;
+use \ReflectionMethod;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\Security\Core\SecurityContext;
+
+/**
+ * Modifies the container, and sets the proxy classes where needed
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class SecureMethodInvocationsPass implements CompilerPassInterface
+{
+ private $cacheDir;
+ private $generator;
+ private $cacheMetadata;
+
+ public function __construct($cacheDir)
+ {
+ $cacheDir .= '/security/';
+ if (!file_exists($cacheDir)) {
+ @mkdir($cacheDir, 0777, true);
+ }
+ if (false === is_writable($cacheDir)) {
+ throw new \RuntimeException('Cannot write to cache folder: '.$cacheDir);
+ }
+ $this->cacheDir = $cacheDir;
+
+ if (!file_exists($cacheDir.'SecurityProxies/')) {
+ @mkdir($cacheDir.'SecurityProxies/', 0777, true);
+ }
+ if (false === is_writeable($cacheDir.'SecurityProxies/')) {
+ throw new \RuntimeException('Cannot write to cache folder: '.$cacheDir.'SecurityProxies/');
+ }
+
+ $this->generator = new ProxyClassGenerator();
+ $this->createOrLoadCacheMetadata();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function process(ContainerBuilder $container)
+ {
+ if (!$container->hasDefinition('security.access.method_interceptor')) {
+ return;
+ }
+
+ $services = $container->findTaggedServiceIds('security.secure_service');
+ $secureNotAll = !$container->getParameter('security.extra.secure_all_services');
+
+ $parameterBag = $container->getParameterBag();
+ foreach ($container->getDefinitions() as $id => $definition) {
+ if ($secureNotAll && !isset($services[$id])) {
+ continue;
+ }
+
+ if ((null === $class = $definition->getClass()) || !class_exists($class)) {
+ if ($secureNotAll) {
+ throw new \RuntimeException(sprintf('Could not find class "%s" for "%s".', $class, $id));
+ }
+
+ continue;
+ }
+
+ if (null !== $definition->getFactoryMethod() || $definition->isAbstract() || $definition->isSynthetic()) {
+ if ($secureNotAll) {
+ throw new \RuntimeException(sprintf('You cannot secure service "%s", because it is either created by a factory, or an abstract/synthetic service.', $id));
+ }
+
+ continue;
+ }
+
+ $this->processDefinition($container, $id, $definition);
+ }
+
+ $this->writeCacheMetadata();
+ }
+
+ private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
+ {
+ if ($this->needsReAssessment($id, $definition)) {
+ $analyzer = new ServiceAnalyzer($definition->getClass(), $container->get('annotation_reader'));
+ $analyzer->analyze();
+
+ $files = array();
+ foreach ($analyzer->getFiles() as $file) {
+ $container->addResource($file = new FileResource($file));
+ $files[] = $file;
+ }
+
+ $metadata = $analyzer->getMetadata();
+ $proxyClass = $path = null;
+ if (true === $metadata->isProxyRequired()) {
+ list($newClassName, $content) = $this->generator->generate($definition, $metadata);
+ file_put_contents($path = $this->cacheDir.'SecurityProxies/'.$newClassName.'.php', $content);
+ $definition->setFile($path);
+ $definition->setClass($proxyClass = 'SecurityProxies\\'.$newClassName);
+ $definition->addMethodCall('jmsSecurityExtraBundle__setMethodSecurityInterceptor', array(new Reference('security.access.method_interceptor')));
+ } else if (isset($this->cacheMetadata[$id]['proxy_class'])) {
+ @unlink($this->cacheDir.$this->cacheMetadata[$id]['proxy_class'].'.php');
+ }
+
+ $this->cacheMetadata[$id] = array(
+ 'class' => $definition->getClass(),
+ 'proxy_class' => $proxyClass,
+ 'proxy_file' => $path,
+ 'analyze_time' => time(),
+ 'files' => $files,
+ );
+ } else {
+ foreach ($this->cacheMetadata[$id]['files'] as $file) {
+ $container->addResource($file);
+ }
+
+ if (null !== $proxyClass = $this->cacheMetadata[$id]['proxy_class']) {
+ $definition->setFile($this->cacheMetadata[$id]['proxy_file']);
+ $definition->setClass($proxyClass);
+ $definition->addMethodCall('jmsSecurityExtraBundle__setMethodSecurityInterceptor', array(new Reference('security.access.method_interceptor')));
+ }
+ }
+ }
+
+ private function needsReAssessment($id, Definition $definition)
+ {
+ if (!isset($this->cacheMetadata[$id])) {
+ return true;
+ }
+
+ $metadata = $this->cacheMetadata[$id];
+ if ($metadata['class'] !== $definition->getClass()) {
+ return true;
+ }
+
+ $lastAnalyzed = $metadata['analyze_time'];
+ foreach ($metadata['files'] as $file) {
+ if (false === $file->isFresh($lastAnalyzed)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private function createOrLoadCacheMetadata()
+ {
+ if (file_exists($this->cacheDir.'cache.meta')) {
+ if (!is_readable($this->cacheDir.'cache.meta')) {
+ throw new \RuntimeException('Cannot load security cache meta data from: '.$this->cacheDir.'cache.meta');
+ }
+
+ $this->cacheMetadata = unserialize(file_get_contents($this->cacheDir.'cache.meta'));
+ } else {
+ set_time_limit(0);
+ $this->cacheMetadata = array();
+ }
+ }
+
+ private function writeCacheMetadata()
+ {
+ if (false === file_put_contents($this->cacheDir.'cache.meta', serialize($this->cacheMetadata))) {
+ throw new \RuntimeException('Could not write to cache file: '.$this->cacheDir.'cache.meta');
+ }
+ }
+}
\ No newline at end of file