@@ -1810,32 +1810,122 @@ defmodule Ash.Policy.Authorizer do
18101810 authorizer . action . type != :read do
18111811 true
18121812 else
1813- check_context = % { resource: authorizer . resource }
1814-
1815- { any_strict_error? , _authorizer } =
1813+ if Enum . any? ( authorizer . policies , fn policy ->
1814+ { all_conditions_true? , _authorizer } =
1815+ Enum . reduce_while ( policy . condition || [ ] , { true , authorizer } , fn
1816+ { check_module , check_opts } , { _acc , auth } ->
1817+ case Policy . fetch_or_strict_check_fact ( auth , { check_module , check_opts } ) do
1818+ { :ok , true , updated_auth } ->
1819+ { :cont , { true , updated_auth } }
1820+
1821+ _ ->
1822+ { :halt , { false , auth } }
1823+ end
1824+ end )
1825+
1826+ all_conditions_true?
1827+ end ) do
18161828 authorizer . policies
1817- |> Enum . map ( & { & 1 , Policy . policy_expression ( & 1 , check_context ) } )
1818- |> Enum . reduce_while ( { true , authorizer } , fn
1819- { policy , { cond_expr , complete_expr } } , { acc , authorizer } ->
1820- strict? = policy . access_type == :strict
1821-
1822- { cond_expr , authorizer } =
1823- Policy . expand_constants ( cond_expr , authorizer , check_context )
1824-
1825- { complete_expr , authorizer } =
1826- Policy . expand_constants ( complete_expr , authorizer , check_context )
1829+ |> Enum . reduce_while ( false , fn policy , _acc ->
1830+ if policy . access_type == :strict do
1831+ { all_conditions_true? , updated_authorizer } =
1832+ Enum . reduce_while (
1833+ policy . condition || [ ] ,
1834+ { true , authorizer } ,
1835+ fn { check_module , check_opts } , { _acc , auth } ->
1836+ case Policy . fetch_or_strict_check_fact ( auth , { check_module , check_opts } ) do
1837+ { :ok , true , updated_auth } ->
1838+ { :cont , { true , updated_auth } }
1839+
1840+ _ ->
1841+ { :halt , { false , auth } }
1842+ end
1843+ end
1844+ )
18271845
1828- case { cond_expr , complete_expr } do
1829- { true , false } when strict? -> { :halt , { true , authorizer } }
1830- { true , _ } -> { :cont , { false , authorizer } }
1831- _ -> { :cont , { acc , authorizer } }
1846+ if all_conditions_true? and policy_fails_statically? ( updated_authorizer , policy ) do
1847+ { :halt , true }
1848+ else
1849+ { :cont , false }
18321850 end
1851+ else
1852+ { :cont , false }
1853+ end
18331854 end )
1834-
1835- any_strict_error?
1855+ else
1856+ true
1857+ end
18361858 end
18371859 end
18381860
1861+ defp policy_fails_statically? ( authorizer , policy ) do
1862+ Enum . reduce_while ( policy . policies , { :forbidden , authorizer } , fn check , { status , auth } ->
1863+ case check . type do
1864+ :authorize_if ->
1865+ case Policy . fetch_or_strict_check_fact (
1866+ auth ,
1867+ { check . check_module , check . check_opts }
1868+ ) do
1869+ { :ok , true , updated_auth } ->
1870+ { :halt , { :authorized , updated_auth } }
1871+
1872+ { :ok , _ , updated_auth } ->
1873+ { :cont , { status , updated_auth } }
1874+
1875+ { :error , updated_auth } ->
1876+ { :halt , { :forbidden , updated_auth } }
1877+ end
1878+
1879+ :forbid_if ->
1880+ case Policy . fetch_or_strict_check_fact (
1881+ auth ,
1882+ { check . check_module , check . check_opts }
1883+ ) do
1884+ { :ok , true , updated_auth } ->
1885+ { :halt , { :forbidden , updated_auth } }
1886+
1887+ { :ok , _ , updated_auth } ->
1888+ { :cont , { status , updated_auth } }
1889+
1890+ { :error , updated_auth } ->
1891+ { :halt , { :forbidden , updated_auth } }
1892+ end
1893+
1894+ :authorize_unless ->
1895+ case Policy . fetch_or_strict_check_fact (
1896+ auth ,
1897+ { check . check_module , check . check_opts }
1898+ ) do
1899+ { :ok , false , updated_auth } ->
1900+ { :halt , { :authorized , updated_auth } }
1901+
1902+ { :ok , _ , updated_auth } ->
1903+ { :cont , { status , updated_auth } }
1904+
1905+ { :error , updated_auth } ->
1906+ { :halt , { :forbidden , updated_auth } }
1907+ end
1908+
1909+ :forbid_unless ->
1910+ case Policy . fetch_or_strict_check_fact (
1911+ auth ,
1912+ { check . check_module , check . check_opts }
1913+ ) do
1914+ { :ok , false , updated_auth } ->
1915+ { :cont , { :forbidden , updated_auth } }
1916+
1917+ { :ok , _ , updated_auth } ->
1918+ { :cont , { status , updated_auth } }
1919+
1920+ { :error , updated_auth } ->
1921+ { :halt , { :forbidden , updated_auth } }
1922+ end
1923+ end
1924+ end )
1925+ |> elem ( 0 )
1926+ |> Kernel . == ( :forbidden )
1927+ end
1928+
18391929 defp get_policies ( authorizer ) do
18401930 % {
18411931 authorizer
0 commit comments