/document_root/ssp/modules/core/lib/ACL.php

https://github.com/Xavy/SDS · PHP · 307 lines · 165 code · 56 blank · 86 comment · 28 complexity · fa96262694acf561375a29d7d80f68f9 MD5 · raw file

  1. <?php
  2. /**
  3. * Generic library for access control lists.
  4. *
  5. * @package simpleSAMLphp
  6. * @version $Id$
  7. */
  8. class sspmod_core_ACL {
  9. /**
  10. * The access control list, as an array.
  11. *
  12. * @var array
  13. */
  14. private $acl;
  15. /**
  16. * Initializer for this access control list.
  17. *
  18. * @param array|string $acl The access control list.
  19. */
  20. public function __construct($acl) {
  21. assert('is_string($acl) || is_array($acl)');
  22. if (is_string($acl)) {
  23. $acl = self::getById($acl);
  24. }
  25. foreach ($acl as $rule) {
  26. if (!is_array($rule)) {
  27. throw new SimpleSAML_Error_Exception('Invalid rule in access control list: ' . var_export($rule, TRUE));
  28. }
  29. if (count($rule) === 0) {
  30. throw new SimpleSAML_Error_Exception('Empty rule in access control list.');
  31. }
  32. $action = array_shift($rule);
  33. if ($action !== 'allow' && $action !== 'deny') {
  34. throw new SimpleSAML_Error_Exception('Invalid action in rule in access control list: ' . var_export($action, TRUE));
  35. }
  36. }
  37. $this->acl = $acl;
  38. }
  39. /**
  40. * Retrieve an access control list with the given id.
  41. *
  42. * @param string $id The id of the access control list.
  43. * @return array The access control list array.
  44. */
  45. private static function getById($id) {
  46. assert('is_string($id)');
  47. $config = SimpleSAML_Configuration::getOptionalConfig('acl.php');
  48. if (!$config->hasValue($id)) {
  49. throw new SimpleSAML_Error_Exception('No ACL with id ' . var_export($id, TRUE) . ' in config/acl.php.');
  50. }
  51. return $config->getArray($id);
  52. }
  53. /**
  54. * Match the attributes against the access control list.
  55. *
  56. * @param array $attributes The attributes of an user.
  57. * @return boolean TRUE if the user is allowed to access the resource, FALSE if not.
  58. */
  59. public function allows(array $attributes) {
  60. foreach ($this->acl as $rule) {
  61. $action = array_shift($rule);
  62. if (!self::match($attributes, $rule)) {
  63. continue;
  64. }
  65. if ($action === 'allow') {
  66. return TRUE;
  67. } else {
  68. return FALSE;
  69. }
  70. }
  71. }
  72. /**
  73. * Match the attributes against the given rule.
  74. *
  75. * @param array $attributes The attributes of an user.
  76. * @param array $rule The rule we should check.
  77. * @return boolean TRUE if the rule matches, FALSE if not.
  78. */
  79. private static function match(array $attributes, array $rule) {
  80. $op = array_shift($rule);
  81. if ($op === NULL) {
  82. /* An empty rule always matches. */
  83. return TRUE;
  84. }
  85. switch($op) {
  86. case 'and':
  87. return self::opAnd($attributes, $rule);
  88. case 'equals':
  89. return self::opEquals($attributes, $rule);
  90. case 'equals-preg':
  91. return self::opEqualsPreg($attributes, $rule);
  92. case 'has':
  93. return self::opHas($attributes, $rule);
  94. case 'has-preg':
  95. return self::opHasPreg($attributes, $rule);
  96. case 'not':
  97. return !self::match($attributes, $rule);
  98. case 'or':
  99. return self::opOr($attributes, $rule);
  100. default:
  101. throw new SimpleSAML_Error_Exception('Invalid ACL operation: ' . var_export($op. TRUE));
  102. }
  103. }
  104. /**
  105. * 'and' match operator.
  106. *
  107. * @param array $attributes The attributes of an user.
  108. * @param array $rule The rule we should check.
  109. * @return boolean TRUE if the rule matches, FALSE if not.
  110. */
  111. private static function opAnd($attributes, $rule) {
  112. foreach ($rule as $subRule) {
  113. if (!self::match($attributes, $subRule)) {
  114. return FALSE;
  115. }
  116. }
  117. /* All matches. */
  118. return TRUE;
  119. }
  120. /**
  121. * 'equals' match operator.
  122. *
  123. * @param array $attributes The attributes of an user.
  124. * @param array $rule The rule we should check.
  125. * @return boolean TRUE if the rule matches, FALSE if not.
  126. */
  127. private static function opEquals($attributes, $rule) {
  128. $attributeName = array_shift($rule);
  129. if (!array_key_exists($attributeName, $attributes)) {
  130. $attributeValues = array();
  131. } else {
  132. $attributeValues = $attributes[$attributeName];
  133. }
  134. foreach ($rule as $value) {
  135. $found = FALSE;
  136. foreach ($attributeValues as $i => $v) {
  137. if ($value !== $v) {
  138. continue;
  139. }
  140. unset($attributeValues[$i]);
  141. $found = TRUE;
  142. break;
  143. }
  144. if (!$found) {
  145. return FALSE;
  146. }
  147. }
  148. if (!empty($attributeValues)) {
  149. /* One of the attribute values didn't match. */
  150. return FALSE;
  151. }
  152. /* All the values in the attribute matched one in the rule. */
  153. return TRUE;
  154. }
  155. /**
  156. * 'equals-preg' match operator.
  157. *
  158. * @param array $attributes The attributes of an user.
  159. * @param array $rule The rule we should check.
  160. * @return boolean TRUE if the rule matches, FALSE if not.
  161. */
  162. private static function opEqualsPreg($attributes, $rule) {
  163. $attributeName = array_shift($rule);
  164. if (!array_key_exists($attributeName, $attributes)) {
  165. $attributeValues = array();
  166. } else {
  167. $attributeValues = $attributes[$attributeName];
  168. }
  169. foreach ($rule as $pattern) {
  170. $found = FALSE;
  171. foreach ($attributeValues as $i => $v) {
  172. if (!preg_match($pattern, $v)) {
  173. continue;
  174. }
  175. unset($attributeValues[$i]);
  176. $found = TRUE;
  177. break;
  178. }
  179. if (!$found) {
  180. return FALSE;
  181. }
  182. }
  183. if (!empty($attributeValues)) {
  184. /* One of the attribute values didn't match. */
  185. return FALSE;
  186. }
  187. /* All the values in the attribute matched one in the rule. */
  188. return TRUE;
  189. }
  190. /**
  191. * 'has' match operator.
  192. *
  193. * @param array $attributes The attributes of an user.
  194. * @param array $rule The rule we should check.
  195. * @return boolean TRUE if the rule matches, FALSE if not.
  196. */
  197. private static function opHas($attributes, $rule) {
  198. $attributeName = array_shift($rule);
  199. if (!array_key_exists($attributeName, $attributes)) {
  200. $attributeValues = array();
  201. } else {
  202. $attributeValues = $attributes[$attributeName];
  203. }
  204. foreach ($rule as $value) {
  205. if (!in_array($value, $attributeValues, TRUE)) {
  206. return FALSE;
  207. }
  208. }
  209. /* Found all values in the rule in the attribute. */
  210. return TRUE;
  211. }
  212. /**
  213. * 'has-preg' match operator.
  214. *
  215. * @param array $attributes The attributes of an user.
  216. * @param array $rule The rule we should check.
  217. * @return boolean TRUE if the rule matches, FALSE if not.
  218. */
  219. private static function opHasPreg($attributes, $rule) {
  220. $attributeName = array_shift($rule);
  221. if (!array_key_exists($attributeName, $attributes)) {
  222. $attributeValues = array();
  223. } else {
  224. $attributeValues = $attributes[$attributeName];
  225. }
  226. foreach ($rule as $pattern) {
  227. $matches = preg_grep($pattern, $attributeValues);
  228. if (count($matches) === 0) {
  229. return FALSE;
  230. }
  231. }
  232. /* Found all values in the rule in the attribute. */
  233. return TRUE;
  234. }
  235. /**
  236. * 'or' match operator.
  237. *
  238. * @param array $attributes The attributes of an user.
  239. * @param array $rule The rule we should check.
  240. * @return boolean TRUE if the rule matches, FALSE if not.
  241. */
  242. private static function opOr($attributes, $rule) {
  243. foreach ($rule as $subRule) {
  244. if (self::match($attributes, $subRule)) {
  245. return TRUE;
  246. }
  247. }
  248. /* None matches. */
  249. return FALSE;
  250. }
  251. }