add policy-lib mods from feature/policy and add policy tests
authorrautenberg <rautenberg@in-silico.ch>
Thu, 22 Mar 2012 11:23:09 +0000 (12:23 +0100)
committerrautenberg <rautenberg@in-silico.ch>
Thu, 22 Mar 2012 11:23:09 +0000 (12:23 +0100)
lib/policy.rb
test/policy.rb [new file with mode: 0644]

index 8591d52..56a90b7 100644 (file)
@@ -1,28 +1,29 @@
 module OpenTox
   require "rexml/document"
 
-  #Module for policy-processing 
+  #Module for policy-processing
   # @see also http://www.opentox.org/dev/apis/api-1.2/AA for opentox API specs
   # Class Policies corresponds to <policies> container of an xml-policy-fle
-  class Policies 
-  
-    attr_accessor :name, :policies
-    
+  class Policies
+
+    #Hash for policy objects see {Policy Policy}
+    attr_accessor :policies, :name
+
     def initialize()
       @policies = {}
     end
-    
+
     #create new policy instance with name
     # @param [String]name of the policy
     def new_policy(name)
       @policies[name] = Policy.new(name)
     end
-    
+
     #drop a specific policy in a policies instance
     # @param [String]name of the policy
     # @return [Boolean]
     def drop_policy(name)
-      return true if @policies.delete(name) 
+      return true if @policies.delete(name)
     end
 
     #drop all policies in a policies instance
@@ -32,58 +33,63 @@ module OpenTox
       end
       return true
     end
-    
+
     # @return [Array] set of arrays affected by policies
     def uris
-      @policies.collect{ |k,v| v.uris }.flatten.uniq
+      @policies.collect{ |k,v| v.uri }.flatten.uniq
     end
 
-        #drop all policies in a policies instance
+    #list all policy names in a policies instance
+    # @return [Array]
     def names
       out = []
       @policies.each do |name, policy|
-        out << name 
+        out << name
       end
       return out
     end
 
-    #loads a default policy template in policies instance
-    def load_default_policy(user, uri, group="member")    
+    # Loads a default policy template in a policies instance
+    # @param [String]user username in LDAP string of user policy: 'uid=<user>,ou=people,dc=opentox,dc=org'
+    # @param [String]uri URI
+    # @param [String]group groupname in LDAP string of group policy: 'cn=<group>,ou=groups,dc=opentox,dc=org'
+    def load_default_policy(user, uri, group="member")
       template = case user
         when "guest", "anonymous" then "default_guest_policy"
-        else "default_policy"     
+        else "default_policy"
       end
       xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
       self.load_xml(xml)
       datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
-       
+
       @policies["policy_user"].name = "policy_user_#{user}_#{datestring}"
-      @policies["policy_user"].rules["rule_user"].uri = uri
-      @policies["policy_user"].rules["rule_user"].name = "rule_user_#{user}_#{datestring}"
-      @policies["policy_user"].subjects["subject_user"].name = "subject_user_#{user}_#{datestring}"
-      @policies["policy_user"].subjects["subject_user"].value = "uid=#{user},ou=people,dc=opentox,dc=org"
+      @policies["policy_user"].rule.uri = uri
+      @policies["policy_user"].rule.name = "rule_user_#{user}_#{datestring}"
+      @policies["policy_user"].subject.name = "subject_user_#{user}_#{datestring}"
+      @policies["policy_user"].subject.value = "uid=#{user},ou=people,dc=opentox,dc=org"
       @policies["policy_user"].subject_group = "subjects_user_#{user}_#{datestring}"
-            
-      @policies["policy_group"].name = "policy_group_#{group}_#{datestring}" 
-      @policies["policy_group"].rules["rule_group"].uri = uri
-      @policies["policy_group"].rules["rule_group"].name = "rule_group_#{group}_#{datestring}"
-      @policies["policy_group"].subjects["subject_group"].name = "subject_group_#{group}_#{datestring}"
-      @policies["policy_group"].subjects["subject_group"].value = "cn=#{group},ou=groups,dc=opentox,dc=org"
-      @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}" 
+
+      @policies["policy_group"].name = "policy_group_#{group}_#{datestring}"
+      @policies["policy_group"].rule.uri = uri
+      @policies["policy_group"].rule.name = "rule_group_#{group}_#{datestring}"
+      @policies["policy_group"].subject.name = "subject_group_#{group}_#{datestring}"
+      @policies["policy_group"].subject.value = "cn=#{group},ou=groups,dc=opentox,dc=org"
+      @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}"
       return true
-    end    
+    end
 
-    #loads a xml template    
+    #loads a xml template
     def load_xml(xml)
       rexml = REXML::Document.new(xml)
       rexml.elements.each("Policies/Policy") do |pol|    #Policies
         policy_name = pol.attributes["name"]
         new_policy(policy_name)
-        #@policies[policy_name] = Policy.new(policy_name)      
+        #@policies[policy_name] = Policy.new(policy_name)
         rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule") do |r|    #Rules
-          rule_name = r.attributes["name"]        
+          rule_name = r.attributes["name"]
           uri = rexml.elements["Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/ResourceName"].attributes["name"]
-          @policies[policy_name].rules[rule_name] = @policies[policy_name].new_rule(rule_name, uri)
+          @policies[policy_name].rule.name = rule_name
+          @policies[policy_name].uri = uri
           rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/AttributeValuePair") do |attribute_pairs|
             action=nil; value=nil;
             attribute_pairs.each_element do |elem|
@@ -93,163 +99,234 @@ module OpenTox
             if action and value
               case action
               when "GET"
-                @policies[policy_name].rules[rule_name].get    = value
+                @policies[policy_name].rule.get    = value
               when "POST"
-                @policies[policy_name].rules[rule_name].post   = value
+                @policies[policy_name].rule.post   = value
               when "PUT"
-                @policies[policy_name].rules[rule_name].put    = value
-              when "DELETE"    
-                @policies[policy_name].rules[rule_name].delete = value
+                @policies[policy_name].rule.put    = value
+              when "DELETE"
+                @policies[policy_name].rule.delete = value
               end
             end
-          end        
+          end
         end
         rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects") do |subjects|    #Subjects
-          @policies[policy_name].subject_group = subjects.attributes["name"]        
+          @policies[policy_name].subject_group = subjects.attributes["name"]
           rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject") do |s|    #Subject
             subject_name  = s.attributes["name"]
             subject_type  = s.attributes["type"]
             subject_value = rexml.elements["Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject[@name='#{subject_name}']/AttributeValuePair/Value"].text
-            @policies[policy_name].new_subject(subject_name, subject_type, subject_value) if subject_name and subject_type and subject_value
+            if subject_name and subject_type and subject_value
+              @policies[policy_name].subject.name = subject_name
+              @policies[policy_name].type = subject_type
+              @policies[policy_name].value = subject_value
+            end
           end
-        end      
-      end    
+        end
+      end
     end
-    
+
     #generates xml from policies instance
     def to_xml
       doc = REXML::Document.new()
       doc <<  REXML::DocType.new("Policies", "PUBLIC  \"-//Sun Java System Access Manager7.1 2006Q3\n Admin CLI DTD//EN\" \"jar://com/sun/identity/policy/policyAdmin.dtd\"")
       doc.add_element(REXML::Element.new("Policies"))
-      
+
       @policies.each do |name, pol|
         policy = REXML::Element.new("Policy")
         policy.attributes["name"] = pol.name
         policy.attributes["referralPolicy"] = false
         policy.attributes["active"] = true
-        @policies[name].rules.each do |r,rl|
-          rule = @policies[name].rules[r]
-          out_rule = REXML::Element.new("Rule")
-          out_rule.attributes["name"] = rule.name
-          servicename = REXML::Element.new("ServiceName")
-          servicename.attributes["name"]="iPlanetAMWebAgentService"
-          out_rule.add_element(servicename)
-          rescourcename = REXML::Element.new("ResourceName")
-          rescourcename.attributes["name"] = rule.uri
-          out_rule.add_element(rescourcename)
-          
-          ["get","post","delete","put"].each do |act|
-            if rule.method(act).call
-              attribute = REXML::Element.new("Attribute") 
-              attribute.attributes["name"] = act.upcase
-              attributevaluepair = REXML::Element.new("AttributeValuePair")
-              attributevaluepair.add_element(attribute)
-              attributevalue = REXML::Element.new("Value")
-              attributevaluepair.add_element(attributevalue)
-              attributevalue.add_text REXML::Text.new(rule.method(act).call)
-              out_rule.add_element(attributevaluepair)
-              
-            end
+        rule = @policies[name].rule
+        out_rule = REXML::Element.new("Rule")
+        out_rule.attributes["name"] = rule.name
+        servicename = REXML::Element.new("ServiceName")
+        servicename.attributes["name"]="iPlanetAMWebAgentService"
+        out_rule.add_element(servicename)
+        rescourcename = REXML::Element.new("ResourceName")
+        rescourcename.attributes["name"] = rule.uri
+        out_rule.add_element(rescourcename)
+
+        ["get","post","delete","put"].each do |act|
+          if rule.method(act).call
+            attribute = REXML::Element.new("Attribute")
+            attribute.attributes["name"] = act.upcase
+            attributevaluepair = REXML::Element.new("AttributeValuePair")
+            attributevaluepair.add_element(attribute)
+            attributevalue = REXML::Element.new("Value")
+            attributevaluepair.add_element(attributevalue)
+            attributevalue.add_text REXML::Text.new(rule.method(act).call)
+            out_rule.add_element(attributevaluepair)
           end
-          policy.add_element(out_rule)
-        end      
+        end
+        policy.add_element(out_rule)
 
         subjects = REXML::Element.new("Subjects")
         subjects.attributes["name"] = pol.subject_group
         subjects.attributes["description"] = ""
-        @policies[name].subjects.each do |subj, subjs|
-          subject = REXML::Element.new("Subject")
-          subject.attributes["name"] = pol.subjects[subj].name
-          subject.attributes["type"] = pol.subjects[subj].type
-          subject.attributes["includeType"] = "inclusive"
-          attributevaluepair = REXML::Element.new("AttributeValuePair")
-          attribute = REXML::Element.new("Attribute") 
-          attribute.attributes["name"] = "Values"
-          attributevaluepair.add_element(attribute)
-          attributevalue = REXML::Element.new("Value")
-          attributevalue.add_text REXML::Text.new(pol.subjects[subj].value)
-          attributevaluepair.add_element(attributevalue)
-          subject.add_element(attributevaluepair)
-          subjects.add_element(subject)
-        end
+        subj = @policies[name].subject.name
+        subject = REXML::Element.new("Subject")
+        subject.attributes["name"] = pol.subject.name
+        subject.attributes["type"] = pol.subject.type
+        subject.attributes["includeType"] = "inclusive"
+        attributevaluepair = REXML::Element.new("AttributeValuePair")
+        attribute = REXML::Element.new("Attribute")
+        attribute.attributes["name"] = "Values"
+        attributevaluepair.add_element(attribute)
+        attributevalue = REXML::Element.new("Value")
+        attributevalue.add_text REXML::Text.new(pol.subject.value)
+        attributevaluepair.add_element(attributevalue)
+        subject.add_element(attributevaluepair)
+        subjects.add_element(subject)
         policy.add_element(subjects)
         doc.root.add_element(policy)
-      end    
+      end
       out = ""
       doc.write(out, 2)
       return out
-    end  
-    
+    end
+
   end
-  
-  #single policy in a policies instance
-  class Policy 
-  
-    attr_accessor :name, :rules, :subject_group, :subjects
-  
+
+  #single policy in a {Policies Policies} instance
+  class Policy
+
+    attr_accessor :name, :rule, :subject_group, :subject, :value, :type, :uri, :group, :user
+
     def initialize(name)
       @name = name
-      @rules = {}
-      @subject_group = ""
-      @subjects = {}
+      @rule = Rule.new("#{name}_rule", nil)
+      @subject_group = "#{name}_subjects"
+      @subject = Subject.new("#{name}_subject", nil, nil)
     end
-    
-    #create a new rule instance for the policy
-    def new_rule(name, uri)
-      @rules[name] = Rule.new(name, uri)
+
+    # Subject type LDAPUsers or LDAPGroups
+    def type
+      @subject.type
     end
-    
-    #create a new subject instance for the policy 
-    def new_subject(name, type, value)
-      @subjects[name] = Subject.new(name, type, value)
+
+    # Set subject type <LDAPUsers, LDAPGroups>
+    # @param [String],type
+    def type=(type)
+      @subject.type = type
     end
-    
-    # @return [Array] set of uris affected by policy
-    def uris
-      @rules.collect{ |k,v| v.uri }.uniq
+
+    # returns LDAP Distinguished Name (DN) e.g. uid=username,ou=people,dc=opentox,dc=org or cn=membergroup,ou=groups,dc=opentox,dc=org
+    def value
+      @subject.value
+    end
+
+    # sets LDAP Distinguished Name (DN) for policy e.g.
+    # @param [String],LDAPString
+    def value=(value)
+      @subject.value = value
+    end
+
+    # uri affected by policy
+    # @return uri affected by policy
+    def uri
+      @rule.uri
+    end
+
+    # sets uri affected by policy
+    # @param [String] set URI
+    def uri=(uri)
+      @rule.uri = uri
+    end
+
+    # Get the groupname from within the LDAP Distinguished Name (DN)
+    def group
+      return false if !value && type != "LDAPGroups"
+      value.split(",").each{|part| return part.gsub("cn=","") if part.match("cn=")}
+    end
+
+    # Get the username from within the LDAP Distinguished Name (DN)
+    def user
+      return false if !value && type != "LDAPUsers"
+      value.split(",").each{|part| return part.gsub("uid=","") if part.match("uid=")}
+    end
+
+    # helper method sets value and type to opentox LDAP Distinguished Name (DN) of a user
+    def set_ot_user(username)
+      self.value = "uid=#{username},ou=people,dc=opentox,dc=org"
+      self.type = "LDAPUsers"
+      true
+    end
+
+    def set_ot_group(groupname)
+      self.value = "cn=#{groupname},ou=groups,dc=opentox,dc=org"
+      self.type = "LDAPGroups"
+      true
     end
-    
+
     #rule inside a policy
     class Rule
-      
-      attr_accessor :name, :uri, :get, :post, :put, :delete
-      
+
+      attr_accessor :name, :uri, :get, :post, :put, :delete, :read, :readwrite
+
       def initialize(name, uri)
         @name = name
         @uri = uri
       end
-      
-      def rename(new, old)
-        self[new] = self.delete(old)
-        self[new].name = new
-      end
-      
+
+      #Set Rule attribute for request-method GET
+      # @param [String]value (allow,deny,nil)
       def get=(value)
         @get = check_value(value, @get)
       end
-    
+
+      #Set Rule attribute for request-method POST
+      # @param [String]value (allow,deny,nil)
       def post=(value)
         @post = check_value(value, @post)
       end
-          
+
+      #Set Rule attribute for request-method DELETE
+      # @param [String]value (allow,deny,nil)
       def delete=(value)
         @delete = check_value(value, @delete)
       end
-      
+
+      #Set Rule attribute for request-method PUT
+      # @param [String]value (allow,deny,nil)
       def put=(value)
         @put = check_value(value, @put)
       end
-          
+
+      def read
+        return true if @get == "allow" && (@put == "deny" || !@put) && (@post == "deny" || !@post)
+      end
+
+      def readwrite
+        return true if @get == "allow" && @put == "allow" && @post == "allow"
+      end
+
+      def read=(value)
+        if value
+          @get = "allow"; @put = nil; @post = nil
+        else
+          @get = nil; @put = nil; @post = nil
+        end
+      end
+
+      def readwrite=(value)
+        if value
+          @get = "allow"; @put = "allow"; @post = "allow"
+        else
+          @get = nil; @put = nil; @post = nil
+        end
+      end
+
       private
-      #checks if value is allow or deny. returns old value if not valid. 
+      #checks if value is allow, deny or nil. returns old value if not valid.
       def check_value(new_value, old_value)
-        return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value 
+        return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value
       end
     end
-    
+
     class Subject
 
-      attr_accessor :name, :type, :value  
+      attr_accessor :name, :type, :value
 
       def initialize(name, type, value)
         @name  = name
@@ -258,4 +335,4 @@ module OpenTox
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/test/policy.rb b/test/policy.rb
new file mode 100644 (file)
index 0000000..eb7e2b6
--- /dev/null
@@ -0,0 +1,120 @@
+require 'test/unit'
+$LOAD_PATH << File.join(File.dirname(__FILE__),'..','lib')
+require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','opentox-client.rb'))
+
+TEST_URI    = "http://only_a_test/test/" + rand(1000000).to_s
+USER_TYPE   = "LDAPUsers"
+USER_VALUE  = "uid=guest,ou=people,dc=opentox,dc=org"
+USER_GROUP  = "member"
+GROUP_TYPE  = "LDAPGroups"
+GROUP_VALUE = "cn=member,ou=groups,dc=opentox,dc=org"
+POLICY_NAME = "test_policy_#{rand(100000)}"
+RULE_NAME = "test_rule_#{rand(100000)}"
+SUBJECT_NAME = "test_subject_#{rand(100000)}"
+
+AA ||= "https://opensso.in-silico.ch"
+AA_USER = "guest"
+AA_PASS = "guest"
+
+@@subjectid = OpenTox::Authorization.authenticate(AA_USER,AA_PASS)
+
+class PolicyTest < Test::Unit::TestCase
+
+  def test_01_class
+    policies = OpenTox::Policies.new()
+    assert_equal(policies.class, OpenTox::Policies)
+    assert_kind_of Array, policies.names
+    assert_kind_of Array, policies.uris
+    assert_kind_of Array, policies.names
+  end
+
+  def test_02_subclasses
+    policies = OpenTox::Policies.new()
+    policies.new_policy(POLICY_NAME)
+    assert_equal(policies.names[0], POLICY_NAME)
+    assert_equal(policies.policies[policies.names[0]].class, OpenTox::Policy)
+    policy = policies.policies[policies.names[0]]
+    policy.rule.name = RULE_NAME
+    policy.uri = TEST_URI
+    assert_equal(policy.rule.class, OpenTox::Policy::Rule)
+    assert_equal(policy.rule.name, RULE_NAME)
+    assert_equal(policy.rule.uri, TEST_URI)
+    assert_equal(policy.uri, TEST_URI)
+    policy.subject.name = SUBJECT_NAME
+    policy.type = USER_TYPE
+    policy.value = USER_VALUE
+    assert_equal(policy.subject.class, OpenTox::Policy::Subject)
+    assert_equal(policy.subject.name, SUBJECT_NAME)
+    assert_equal(policy.subject.type, USER_TYPE)
+    assert_equal(policy.type, USER_TYPE)
+    assert_equal(policy.subject.value, USER_VALUE)
+    assert_equal(policy.value, USER_VALUE)
+  end
+
+  def test_03_read_readwrite
+    policies = OpenTox::Policies.new()
+    policies.new_policy(POLICY_NAME)
+    policy = policies.policies[policies.names[0]]
+    policy.rule.name = RULE_NAME
+    policy.uri = TEST_URI
+    policy.rule.get = "allow"
+    assert policy.rule.read
+    assert !policy.rule.readwrite
+    policy.rule.post = "allow"
+    policy.rule.put = "allow"
+    assert !policy.rule.read
+    assert policy.rule.readwrite
+  end
+
+  def test_04_group_user
+    policies = OpenTox::Policies.new()
+    policies.load_default_policy(AA_USER, TEST_URI, "member")
+    assert_equal "member", policies.policies["policy_group"].group
+    assert_equal AA_USER, policies.policies["policy_user"].user
+  end
+
+  def test_05_DN
+    policies = OpenTox::Policies.new()
+    policies.new_policy(POLICY_NAME)
+    policy = policies.policies[policies.names[0]]
+    policy.set_ot_user(AA_USER)
+    assert_equal USER_VALUE, policy.value
+    assert_equal USER_TYPE, policy.type
+    policy.set_ot_group(USER_GROUP)
+    assert_equal GROUP_VALUE, policy.value
+    assert_equal GROUP_TYPE, policy.type
+  end
+
+  def test_06_load_xml_and_check_defaults
+    policies = OpenTox::Policies.new()
+    xml = File.read(File.join(File.dirname(__FILE__), "../lib/templates/default_policy.xml"))
+    policies.load_xml(xml)
+    # check user policy
+    policy = policies.policies["policy_user"]
+    assert policy.name == "policy_user"
+    assert policy.rule.name == "rule_user"
+    assert policy.rule.uri == "uri"
+    assert policy.rule.get == "allow"
+    assert policy.rule.post == "allow"
+    assert policy.rule.delete == "allow"
+    assert policy.rule.put == "allow"
+    assert policy.subject_group == "subjects_user"
+    assert policy.subject.name == "subject_user"
+    assert policy.subject.type == USER_TYPE
+    assert policy.subject.value == USER_VALUE
+    # check group policy
+    policy = policies.policies["policy_group"]
+    assert policy.name == "policy_group"
+    assert policy.rule.name == "rule_group"
+    assert policy.rule.uri == "uri"
+    assert policy.rule.get == "allow"
+    assert !policy.rule.post
+    assert !policy.rule.delete
+    assert !policy.rule.put
+    assert policy.subject_group == "subjects_group"
+    assert policy.subject.name == "subject_group"
+    assert policy.subject.type == GROUP_TYPE
+    assert policy.subject.value == GROUP_VALUE
+  end
+
+end
\ No newline at end of file