/Security/AnnotationLoader.php

https://github.com/crocos/CrocosSecurityBundle · PHP · 240 lines · 136 code · 37 blank · 67 comment · 19 complexity · 0c194a4f7e3abaa9eb57a1146565e72a MD5 · raw file

  1. <?php
  2. namespace Crocos\SecurityBundle\Security;
  3. use Crocos\SecurityBundle\Annotation\Annotation;
  4. use Crocos\SecurityBundle\Annotation\Secure;
  5. use Crocos\SecurityBundle\Annotation\SecureConfig;
  6. use Crocos\SecurityBundle\Security\AuthLogic\AuthLogicResolver;
  7. use Crocos\SecurityBundle\Security\HttpAuth\HttpAuthFactoryInterface;
  8. use Crocos\SecurityBundle\Security\Role\RoleManagerResolver;
  9. use Doctrine\Common\Annotations\Reader;
  10. use SplPriorityQueue;
  11. /**
  12. * AnnotationLoader.
  13. *
  14. * @author Katsuhiro Ogawa <ogawa@crocos.co.jp>
  15. */
  16. class AnnotationLoader
  17. {
  18. const DEFAULT_AUTH_LOGIC = 'session';
  19. const DEFAULT_ROLE_MANAGER = 'session';
  20. /**
  21. * @var Reader
  22. */
  23. protected $reader;
  24. /**
  25. * @var AuthLogicResolver
  26. */
  27. protected $resolver;
  28. /**
  29. * @var RoleManagerResolver
  30. */
  31. protected $roleManagerResolver;
  32. /**
  33. * @var SplPriorityQueue
  34. */
  35. protected $httpAuthFactories;
  36. /**
  37. * @var ParameterResolverInterface
  38. */
  39. protected $parameterResolver;
  40. /**
  41. * @param Reader $reader Annotation reader
  42. * @param AuthLogicResolver $resolver
  43. * @param RoleManagerResolver $roleManagerResolver
  44. */
  45. public function __construct(Reader $reader, AuthLogicResolver $resolver, RoleManagerResolver $roleManagerResolver)
  46. {
  47. $this->reader = $reader;
  48. $this->resolver = $resolver;
  49. $this->roleManagerResolver = $roleManagerResolver;
  50. $this->httpAuthFactories = new SplPriorityQueue();
  51. }
  52. /**
  53. * @param HttpAuthFactoryInterface $httpAuthFactory
  54. */
  55. public function addHttpAuthFactory(HttpAuthFactoryInterface $httpAuthFactory)
  56. {
  57. $this->httpAuthFactories->insert($httpAuthFactory, $httpAuthFactory->getPriority());
  58. }
  59. /**
  60. * @param ParameterResolverInterface $parameterResolver
  61. */
  62. public function setParameterResolver(ParameterResolverInterface $parameterResolver)
  63. {
  64. $this->parameterResolver = $parameterResolver;
  65. }
  66. /**
  67. * @param SecurityContext $context
  68. * @param \ReflectionClass $class
  69. * @param \ReflectionMethod $method
  70. */
  71. public function load(SecurityContext $context, \ReflectionClass $class, \ReflectionMethod $method)
  72. {
  73. // Retrieve all ancestors (parent first)
  74. $klass = $class;
  75. $klasses = [$klass];
  76. while ($klass = $klass->getParentClass()) {
  77. $klasses[] = $klass;
  78. }
  79. $klasses = array_reverse($klasses);
  80. $annotations = [];
  81. foreach ($klasses as $klass) {
  82. $annotations = array_merge($annotations, $this->reader->getClassAnnotations($klass));
  83. }
  84. $annotations = array_merge($annotations, $this->reader->getMethodAnnotations($method));
  85. foreach ($annotations as $annotation) {
  86. if ($annotation instanceof Annotation) {
  87. $this->loadAnnotation($context, $annotation);
  88. }
  89. }
  90. $this->fixContext($context);
  91. }
  92. /**
  93. * @param SecurityContext $context
  94. * @param Annotation $annotation
  95. */
  96. protected function loadAnnotation(SecurityContext $context, Annotation $annotation)
  97. {
  98. if ($annotation instanceof Secure) {
  99. $this->loadSecureAnnotation($context, $annotation);
  100. } elseif ($annotation instanceof SecureConfig) {
  101. $this->loadSecureConfigAnnotation($context, $annotation);
  102. }
  103. }
  104. /**
  105. * Load @Secure annotation.
  106. *
  107. * @param SecurityContext $context
  108. * @param Secure $annotation
  109. */
  110. protected function loadSecureAnnotation(SecurityContext $context, Secure $annotation)
  111. {
  112. $context->setSecure(!$annotation->disabled());
  113. if (null !== $annotation->allow()) {
  114. $context->setAllowedRoles($annotation->allow());
  115. }
  116. }
  117. /**
  118. * Load @SecureConfig annotation.
  119. *
  120. * @param SecurityContext $context
  121. * @param SecureConfig $annotation
  122. */
  123. protected function loadSecureConfigAnnotation(SecurityContext $context, SecureConfig $annotation)
  124. {
  125. if (null !== $annotation->domain()) {
  126. $context->setDomain($annotation->domain());
  127. }
  128. if (null !== $annotation->httpsRequired()) {
  129. $context->setHttpsRequired($annotation->httpsRequired());
  130. }
  131. if (null !== $annotation->options()) {
  132. $context->setOptions($this->resolveParameter($annotation->options()));
  133. }
  134. if (null !== $annotation->auth()) {
  135. $context->setAuthLogic($this->resolver->resolveAuthLogic($this->resolveParameter($annotation->auth())));
  136. }
  137. if (null !== $annotation->roleManager()) {
  138. $context->setRoleManager($this->roleManagerResolver->resolveRoleManager($this->resolveParameter($annotation->roleManager())));
  139. }
  140. if (null !== $annotation->forward()) {
  141. $context->setForwardingController($this->resolveParameter($annotation->forward()));
  142. }
  143. $this->loadHttpAuth($context, $annotation);
  144. }
  145. /**
  146. * Fix security context.
  147. *
  148. * @param SecurityContext $context
  149. */
  150. protected function fixContext(SecurityContext $context)
  151. {
  152. if (null === $context->getAuthLogic()) {
  153. $context->setAuthLogic($this->resolver->resolveAuthLogic(self::DEFAULT_AUTH_LOGIC));
  154. }
  155. if (null === $context->getRoleManager()) {
  156. $context->setRoleManager($this->roleManagerResolver->resolveRoleManager(self::DEFAULT_ROLE_MANAGER));
  157. }
  158. if ($context->getAuthLogic() instanceof SecureOptionsAcceptableInterface) {
  159. $context->getAuthLogic()->setOptions($context->getOptions());
  160. }
  161. $context->fixDomain();
  162. }
  163. /**
  164. * @param SecurityContext $context
  165. * @param SecureConfig $annotation
  166. */
  167. protected function loadHttpAuth(SecurityContext $context, SecureConfig $annotation)
  168. {
  169. if (count($this->httpAuthFactories) === 0) {
  170. return;
  171. }
  172. foreach ($this->httpAuthFactories as $httpAuthFactory) {
  173. $name = $httpAuthFactory->getName();
  174. $value = $annotation->{$name}();
  175. if ($value === null) {
  176. continue;
  177. }
  178. $value = $this->resolveParameter($value);
  179. if (in_array($value, [null, false, '', []], true)) {
  180. continue;
  181. }
  182. $httpAuth = $httpAuthFactory->create($value, $context->getDomain());
  183. if ($httpAuth) {
  184. $context->enableHttpAuth($name, $httpAuth);
  185. }
  186. }
  187. }
  188. /**
  189. * @param mixed $value
  190. *
  191. * @return string
  192. */
  193. protected function resolveParameter($value)
  194. {
  195. if ($this->parameterResolver === null) {
  196. return $value;
  197. }
  198. if (!is_string($value)) {
  199. return $value;
  200. }
  201. return $this->parameterResolver->resolveValue($value);
  202. }
  203. }