----------------------------------------------------------------------- -- security-policies-urls -- URL security policy -- Copyright (C) 2010, 2011, 2012, 2017, 2018, 2019 Stephane Carrez -- Written by Stephane Carrez (Stephane.Carrez@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. ----------------------------------------------------------------------- with Ada.Containers.Hashed_Maps; with Ada.Containers.Vectors; with Util.Refs; with Util.Strings; with Util.Serialize.Mappers; with GNAT.Regexp; with Security.Contexts; -- == URL Security Policy == -- The `Security.Policies.Urls` implements a security policy intended to be used -- in web servers. It allows to protect an URL by defining permissions that must be granted -- for a user to get access to the URL. A typical example is a web server that has a set of -- administration pages, these pages should be accessed by users having some admin permission. -- -- === Policy creation === -- An instance of the `URL_Policy` must be created and registered in the policy manager. -- Get or declare the following variables: -- -- Manager : Security.Policies.Policy_Manager; -- Policy : Security.Policies.Urls.URL_Policy_Access; -- -- Create the URL policy and register it in the policy manager as follows: -- -- Policy := new URL_Policy; -- Manager.Add_Policy (Policy.all'Access); -- -- === Policy Configuration === -- Once the URL policy is registered, the policy manager can read and process the following -- XML configuration: -- -- -- -- create-workspace -- admin -- /workspace/create -- /workspace/setup/* -- -- ... -- -- -- This policy gives access to the URL that match one of the URL pattern if the -- security context has the permission `create-workspace` or `admin`. -- These two permissions are checked according to another security policy. -- The XML configuration can define several `url-policy`. They are checked in -- the order defined in the XML. In other words, the first `url-policy` that matches -- the URL is used to verify the permission. -- -- The `url-policy` definition can contain several `permission`. -- The first permission that is granted gives access to the URL. -- -- === Checking for permission === -- To check a URL permission, you must declare a `URL_Permission` object with the URL. -- -- URL : constant String := ...; -- Perm : constant Policies.URLs.URL_Permission (URL'Length) -- := URL_Permission '(Len => URI'Length, URL => URL); -- -- Then, we can check the permission: -- -- Result : Boolean := Security.Contexts.Has_Permission (Perm); -- package Security.Policies.URLs is NAME : constant String := "URL-Policy"; package P_URL is new Security.Permissions.Definition ("url"); -- ------------------------------ -- URL Permission -- ------------------------------ -- Represents a permission to access a given URL. type URL_Permission (Len : Natural) is new Permissions.Permission (P_URL.Permission) with record URL : String (1 .. Len); end record; -- ------------------------------ -- URL policy -- ------------------------------ type URL_Policy is new Policy with private; type URL_Policy_Access is access all URL_Policy'Class; Invalid_Name : exception; -- Get the policy name. overriding function Get_Name (From : in URL_Policy) return String; -- Returns True if the user has the permission to access the given URI permission. function Has_Permission (Manager : in URL_Policy; Context : in Contexts.Security_Context'Class; Permission : in URL_Permission'Class) return Boolean; -- Grant the permission to access to the given URI to users having the To -- permissions. procedure Grant_URI_Permission (Manager : in out URL_Policy; URI : in String; To : in String); -- Initialize the permission manager. overriding procedure Initialize (Manager : in out URL_Policy); -- Finalize the permission manager. overriding procedure Finalize (Manager : in out URL_Policy); -- Setup the XML parser to read the policy description. overriding procedure Prepare_Config (Policy : in out URL_Policy; Mapper : in out Util.Serialize.Mappers.Processing); -- Get the URL policy associated with the given policy manager. -- Returns the URL policy instance or null if it was not registered in the policy manager. function Get_URL_Policy (Manager : in Security.Policies.Policy_Manager'Class) return URL_Policy_Access; private use Util.Strings; -- The Access_Rule represents a list of permissions to verify to grant -- access to the resource. To make it simple, the user must have one of the -- permission from the list. Each permission will refer to a specific permission -- controller. type Access_Rule (Count : Natural) is new Util.Refs.Ref_Entity with record Permissions : Permission_Index_Array (1 .. Count); end record; type Access_Rule_Access is access all Access_Rule; package Access_Rule_Refs is new Util.Refs.Indefinite_References (Element_Type => Access_Rule, Element_Access => Access_Rule_Access); subtype Access_Rule_Ref is Access_Rule_Refs.Ref; -- Find the access rule of the policy that matches the given URI. -- Returns the No_Rule value (disable access) if no rule is found. function Find_Access_Rule (Manager : in URL_Policy; URI : in String) return Access_Rule_Ref; -- The Policy defines the access rules that are applied on a given -- URL, set of URLs or files. type Policy is record Id : Natural; Pattern : GNAT.Regexp.Regexp; Rule : Access_Rule_Ref; end record; -- The Policy_Vector represents the whole permission policy. The order of -- policy in the list is important as policies can override each other. package Policy_Vector is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Policy); package Rules_Maps is new Ada.Containers.Hashed_Maps (Key_Type => String_Ref, Element_Type => Access_Rule_Ref, Hash => Hash, Equivalent_Keys => Equivalent_Keys, "=" => Access_Rule_Refs."="); type Rules is new Util.Refs.Ref_Entity with record Map : Rules_Maps.Map; end record; type Rules_Access is access all Rules; package Rules_Ref is new Util.Refs.References (Rules, Rules_Access); package Atomic_Rules_Ref is new Rules_Ref.IR.Atomic; type Rules_Ref_Access is access Atomic_Rules_Ref.Atomic_Ref; type Controller_Access_Array_Access is access all Controller_Access_Array; type URL_Policy is new Security.Policies.Policy with record Cache : Rules_Ref_Access; Policies : Policy_Vector.Vector; Id : Natural := 0; Permissions : Util.Beans.Objects.Vectors.Vector; Patterns : Util.Beans.Objects.Vectors.Vector; end record; end Security.Policies.URLs;