public function convertMethodAnnotations(\ReflectionMethod $method, array $annotations) { $parameters = array(); foreach ($method->getParameters() as $index => $parameter) { $parameters[$parameter->getName()] = $index; } $methodMetadata = new MethodMetadata($method->getDeclaringClass()->getName(), $method->getName()); foreach ($annotations as $annotation) { if ($annotation instanceof Secure) { $methodMetadata->roles = $annotation->roles; } else { if ($annotation instanceof SecureParam) { if (!isset($parameters[$annotation->name])) { throw new \InvalidArgumentException(sprintf('The parameter "%s" does not exist for method "%s".', $annotation->name, $method->getName())); } $methodMetadata->addParamPermissions($parameters[$annotation->name], $annotation->permissions); } else { if ($annotation instanceof SecureReturn) { $methodMetadata->returnPermissions = $annotation->permissions; } else { if ($annotation instanceof SatisfiesParentSecurityPolicy) { $methodMetadata->satisfiesParentSecurityPolicy = true; } else { if ($annotation instanceof RunAs) { $methodMetadata->runAsRoles = $annotation->roles; } } } } } } return $methodMetadata; }
private function getMethodSecurityMetadata(MethodMetadata $method) { $metadata = var_export($method->getAsArray(), true); $staticReplaces = array("\n" => '', 'array (' => 'array('); $metadata = strtr($metadata, $staticReplaces); $regexReplaces = array('/\\s+/' => ' ', '/\\(\\s+/' => '(', '/[0-9]+\\s+=>\\s+/' => '', '/,\\s*\\)/' => ')'); $metadata = preg_replace(array_keys($regexReplaces), array_values($regexReplaces), $metadata); return $metadata; }
private function convertMethodAnnotations(\ReflectionMethod $method, array $annotations, PreAuthorize $classPreAuthorize = null) { $parameters = array(); foreach ($method->getParameters() as $index => $parameter) { $parameters[$parameter->getName()] = $index; } $methodMetadata = new MethodMetadata($method->class, $method->name); $hasSecurityMetadata = $hasPreRestrictions = false; foreach ($annotations as $annotation) { if ($annotation instanceof Secure) { $methodMetadata->roles = $annotation->roles; $hasSecurityMetadata = $hasPreRestrictions = true; } elseif ($annotation instanceof PreAuthorize) { $methodMetadata->roles = array(new Expression($annotation->expr)); $hasSecurityMetadata = $hasPreRestrictions = true; } elseif ($annotation instanceof SecureParam) { if (!isset($parameters[$annotation->name])) { throw new InvalidArgumentException(sprintf('The parameter "%s" does not exist for method "%s".', $annotation->name, $method->name)); } $methodMetadata->addParamPermissions($parameters[$annotation->name], $annotation->permissions); $hasSecurityMetadata = $hasPreRestrictions = true; } elseif ($annotation instanceof SecureReturn) { $methodMetadata->returnPermissions = $annotation->permissions; $hasSecurityMetadata = true; } elseif ($annotation instanceof SatisfiesParentSecurityPolicy) { $methodMetadata->satisfiesParentSecurityPolicy = true; $hasSecurityMetadata = true; } elseif ($annotation instanceof RunAs) { $methodMetadata->runAsRoles = $annotation->roles; $hasSecurityMetadata = true; } } // We use the following conditions to determine whether we should apply // a class-level @PreAuthorize annotation: // // - No other authorization that runs before the method invocation // must be configured. @Secure, @SecureParam, @PreAuthorize must // not be present; @SecureReturn would be fine though. // // - The method must be public, or alternatively publicOnly on // @PreAuthorize must be set to false. if (!$hasPreRestrictions && $classPreAuthorize && (!$classPreAuthorize->publicOnly || !$method->isProtected())) { $methodMetadata->roles = array(new Expression($classPreAuthorize->expr)); $hasSecurityMetadata = true; } return $hasSecurityMetadata ? $methodMetadata : null; }
private function normalizeMetadata() { $secureMethods = array(); foreach ($this->metadata->classMetadata as $class) { if ($class->reflection->isFinal()) { throw new \RuntimeException('Final classes cannot be secured.'); } foreach ($class->methodMetadata as $name => $method) { if ($method->reflection->isStatic() || $method->reflection->isFinal()) { throw new \RuntimeException('Annotations cannot be defined on final, or static methods.'); } if (!isset($secureMethods[$name])) { $this->metadata->addMethodMetadata($method); $secureMethods[$name] = $method; } else { if ($method->reflection->isAbstract()) { $secureMethods[$name]->merge($method); } else { if (false === $secureMethods[$name]->satisfiesParentSecurityPolicy && $method->reflection->getDeclaringClass()->getName() !== $secureMethods[$name]->reflection->getDeclaringClass()->getName()) { throw new \RuntimeException(sprintf('Unresolved security metadata conflict for method "%s::%s" in "%s". Please copy the respective annotations, and add @SatisfiesParentSecurityPolicy to the child method.', $secureMethods[$name]->reflection->getDeclaringClass()->getName(), $name, $secureMethods[$name]->reflection->getDeclaringClass()->getFileName())); } } } } } foreach ($secureMethods as $name => $method) { if ($method->reflection->isAbstract()) { $previous = null; $abstractClass = $method->reflection->getDeclaringClass()->getName(); foreach ($this->hierarchy as $refClass) { if ($abstractClass === ($fqcn = $refClass->getName())) { $methodMetadata = new MethodMetadata($previous->getName(), $name); $methodMetadata->merge($method); $this->metadata->addMethodMetadata($methodMetadata); continue 2; } if (!$refClass->isInterface() && $this->hasMethod($refClass, $name)) { $previous = $refClass; } } } } }