-----------------------------------------------------------------------
-- security-contexts -- Context to provide security information and verify permissions
-- Copyright (C) 2011, 2012, 2016, 2022 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.Task_Attributes;
with Ada.Unchecked_Deallocation;
package body Security.Contexts is
use type Security.Policies.Policy_Context_Array_Access;
use type Security.Policies.Policy_Access;
use type Security.Policies.Policy_Context_Access;
package Task_Context is new Ada.Task_Attributes
(Security_Context_Access, null);
procedure Free is
new Ada.Unchecked_Deallocation (Object => Security.Policies.Policy_Context'Class,
Name => Security.Policies.Policy_Context_Access);
-- ------------------------------
-- Get the application associated with the current service operation.
-- ------------------------------
function Get_User_Principal (Context : in Security_Context'Class)
return Security.Principal_Access is
begin
return Context.Principal;
end Get_User_Principal;
-- ------------------------------
-- Get the permission manager.
-- ------------------------------
function Get_Permission_Manager (Context : in Security_Context'Class)
return Security.Policies.Policy_Manager_Access is
begin
return Context.Manager;
end Get_Permission_Manager;
-- ------------------------------
-- Get the policy with the name Name registered in the policy manager.
-- Returns null if there is no such policy.
-- ------------------------------
function Get_Policy (Context : in Security_Context'Class;
Name : in String) return Security.Policies.Policy_Access is
use type Security.Policies.Policy_Manager_Access;
begin
if Context.Manager = null then
return null;
else
return Context.Manager.Get_Policy (Name);
end if;
end Get_Policy;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- Returns True if the permission is granted.
-- ------------------------------
function Has_Permission (Context : in Security_Context;
Permission : in Permissions.Permission_Index) return Boolean is
use type Security.Policies.Policy_Manager_Access;
begin
if Context.Manager = null then
return False;
end if;
declare
Perm : Security.Permissions.Permission (Permission);
begin
return Context.Manager.Has_Permission (Context, Perm);
end;
end Has_Permission;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- Returns True if the permission is granted.
-- ------------------------------
function Has_Permission (Context : in Security_Context;
Permission : in String) return Boolean is
Index : constant Permissions.Permission_Index
:= Permissions.Get_Permission_Index (Permission);
begin
return Security_Context'Class (Context).Has_Permission (Index);
end Has_Permission;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- Returns True if the permission is granted.
-- ------------------------------
function Has_Permission (Context : in Security_Context;
Permission : in Permissions.Permission'Class) return Boolean is
use type Security.Policies.Policy_Manager_Access;
begin
if Context.Manager = null then
return False;
else
return Context.Manager.Has_Permission (Context, Permission);
end if;
end Has_Permission;
-- ------------------------------
-- Initializes the service context. By creating the Security_Context variable,
-- the instance will be associated with the current task attribute. If the current task
-- already has a security context, the new security context is installed, the old one
-- being kept.
-- ------------------------------
overriding
procedure Initialize (Context : in out Security_Context) is
begin
Context.Previous := Task_Context.Value;
-- If we already have a security context, setup the manager and user principal.
if Context.Previous /= null then
Context.Manager := Context.Previous.Manager;
Context.Principal := Context.Previous.Principal;
end if;
Task_Context.Set_Value (Context'Unchecked_Access);
end Initialize;
-- ------------------------------
-- Finalize the security context releases any object. The previous security context is
-- restored to the current task attribute.
-- ------------------------------
overriding
procedure Finalize (Context : in out Security_Context) is
procedure Free is
new Ada.Unchecked_Deallocation (Object => Security.Policies.Policy_Context_Array,
Name => Security.Policies.Policy_Context_Array_Access);
begin
Task_Context.Set_Value (Context.Previous);
if Context.Contexts /= null then
for I in Context.Contexts'Range loop
Free (Context.Contexts (I));
end loop;
Free (Context.Contexts);
end if;
end Finalize;
-- ------------------------------
-- Set a policy context information represented by Value and associated with
-- the policy index Policy.
-- ------------------------------
procedure Set_Policy_Context (Context : in out Security_Context;
Policy : in Security.Policies.Policy_Access;
Value : in Security.Policies.Policy_Context_Access) is
begin
if Context.Contexts = null then
Context.Contexts := Context.Manager.Create_Policy_Contexts;
end if;
Free (Context.Contexts (Policy.Get_Policy_Index));
Context.Contexts (Policy.Get_Policy_Index) := Value;
end Set_Policy_Context;
-- ------------------------------
-- Get the policy context information registered for the given security policy in the security
-- context Context.
-- Raises Invalid_Context if there is no such information.
-- Raises Invalid_Policy if the policy was not set.
-- ------------------------------
function Get_Policy_Context (Context : in Security_Context;
Policy : in Security.Policies.Policy_Access)
return Security.Policies.Policy_Context_Access is
Result : Security.Policies.Policy_Context_Access;
begin
if Policy = null then
raise Invalid_Policy;
end if;
if Context.Contexts = null then
raise Invalid_Context;
end if;
Result := Context.Contexts (Policy.Get_Policy_Index);
return Result;
end Get_Policy_Context;
-- ------------------------------
-- Returns True if a context information was registered for the security policy.
-- ------------------------------
function Has_Policy_Context (Context : in Security_Context;
Policy : in Security.Policies.Policy_Access) return Boolean is
begin
return Policy /= null and then Context.Contexts /= null
and then Context.Contexts (Policy.Get_Policy_Index) /= null;
end Has_Policy_Context;
-- ------------------------------
-- Set the current application and user context.
-- ------------------------------
procedure Set_Context (Context : in out Security_Context;
Manager : in Security.Policies.Policy_Manager_Access;
Principal : in Security.Principal_Access) is
use type Security.Policies.Policy_Manager_Access;
begin
if Manager /= null then
Context.Manager := Manager;
end if;
if Principal /= null then
Context.Principal := Principal;
end if;
if Manager = null and then Principal = null then
raise Invalid_Context with "There is no policy manager and no user principal";
end if;
end Set_Context;
-- ------------------------------
-- Get the current security context.
-- Returns null if the current thread is not associated with any security context.
-- ------------------------------
function Current return Security_Context_Access is
begin
return Task_Context.Value;
end Current;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- ------------------------------
function Has_Permission (Permission : in Permissions.Permission_Index) return Boolean is
Context : constant Security_Context_Access := Current;
begin
if Context = null then
return False;
else
return Context.Has_Permission (Permission);
end if;
end Has_Permission;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- ------------------------------
function Has_Permission (Permission : in String) return Boolean is
Context : constant Security_Context_Access := Current;
begin
if Context = null then
return False;
else
return Context.Has_Permission (Permission);
end if;
end Has_Permission;
-- ------------------------------
-- Check if the permission identified by Permission is allowed according to
-- the current security context.
-- ------------------------------
function Has_Permission (Permission : in Permissions.Permission'Class) return Boolean is
Context : constant Security_Context_Access := Current;
begin
if Context = null then
return False;
else
return Context.Has_Permission (Permission);
end if;
end Has_Permission;
end Security.Contexts;