Hi,
The moment's here, I'd like to share my code with you now. Let me
comment on some additions from my last post here in August.
The methods for testing HBAC rules in hbactest module were modified so
that a time zone can now also be picked in case there are some rules
with the "host" time zone in the rule time policy. I also added few
tests that test setting accessTime values.
The most important update of the previous month is the addition of
negative values to the time rules language. Most of the keywords (all,
except for timeofday and year) now accept negative values and negative
value ranges. This should be useful for cases when the user should only
be allowed access e.g. in the last 7 days of a month, last few weeks of
a year etc. Also, it is a similar behavior to what iCalendar has.
The addition of negative values also made me re-think the ways the week
of a year should be calculated. There are no 0th weeks of year anymore,
a week of year can hold values ranging from 1 to 53 where the 1st week
of a year may appear even on a date of the previous year (if 1st January
is Tue-Thu) or the 52nd or 53rd week may appear on a date of the
following year (when 31st December is Thu-Sat). If my explanation seems
rather rough, please see
https://docs.oracle.com/javase/8/docs/api/java/time/temporal/WeekFields.html.
The latter caused some changes to be made in my SSSD code. These changes
took the most of my time last month alongside with generally polishing
the code and adding comments where I thought necessary. I will push my
SSSD code to the sssd-devel mailing list as a follow-up to this mail.
Another thing - I updated the design page on the FreeIPA wiki, so please
check it out, too
(http://www.freeipa.org/page/V4/Time-Based_Account_Policies).
Last thing I would like to mention - there is now a copr repo with both
sssd and freeipa with time-based policies
(https://copr.fedoraproject.org/coprs/stlaz/freeipa-sssd-timerules/).
This was Martin K.'s idea and I think it's pretty dandy :) As the
patches I am posting only contain CLI for HBAC time policies, you might
be pleased that the repo includes at least basic WebUI for this purpose
(although the WebUI is for some reason not updating the page on rule
addition properly, I will be hopefully looking into that shortly). You
will still need mkosek/freeipa-master copr repo for some dependencies.
Should it not work properly for you, please, send me an email, it's my
first time taking care of a copr repo.
That's it from me for now, thank you for your patience with my emails,
Standa
From 552d23f8c900cb3ef5437f020874f968bfce35e9 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 7 Jul 2015 09:44:23 +0200
Subject: [PATCH 2/8] Added time-based policies types to LDAP schema.
https://fedorahosted.org/freeipa/ticket/547
---
install/share/60basev2.ldif | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/install/share/60basev2.ldif b/install/share/60basev2.ldif
index 00712ddda2c548b7f7924a012f3f68499f2f01da..c3251a4331005ade1333f9e64b57a62a89706ce9 100644
--- a/install/share/60basev2.ldif
+++ b/install/share/60basev2.ldif
@@ -37,7 +37,9 @@ attributeTypes: (2.16.840.1.113730.3.8.3.11 NAME 'externalHost' DESC 'Multivalue
attributeTypes: (2.16.840.1.113730.3.8.3.12 NAME 'sourceHostCategory' DESC 'Additional classification for hosts' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
attributeTypes: (2.16.840.1.113730.3.8.3.13 NAME 'accessRuleType' DESC 'The flag to represent if it is allow or deny rule.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
attributeTypes: (2.16.840.1.113730.3.8.3.14 NAME 'accessTime' DESC 'Access time' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
-objectClasses: (2.16.840.1.113730.3.8.4.7 NAME 'ipaHBACRule' SUP ipaAssociation STRUCTURAL MUST accessRuleType MAY ( sourceHost $ sourceHostCategory $ serviceCategory $ memberService $ externalHost $ accessTime ) X-ORIGIN 'IPA v2' )
+attributeTypes: (2.16.840.1.113730.3.8.11.72 NAME 'accessTimeExclude' DESC 'Access time - exclude these values' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4' )
+attributeTypes: (2.16.840.1.113730.3.8.11.73 NAME 'ipaTimeZone' DESC 'Olson database timezone name' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v4' )
+objectClasses: (2.16.840.1.113730.3.8.4.7 NAME 'ipaHBACRule' SUP ipaAssociation STRUCTURAL MUST accessRuleType MAY ( sourceHost $ sourceHostCategory $ serviceCategory $ memberService $ externalHost $ ipaTimeZone $ accessTime $ accessTimeExclude ) X-ORIGIN 'IPA v2' )
attributeTypes: (2.16.840.1.113730.3.8.3.15 NAME 'nisDomainName' DESC 'NIS domain name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.8 NAME 'ipaNISNetgroup' DESC 'IPA version of NIS netgroup' SUP ipaAssociation STRUCTURAL MAY ( externalHost $ nisDomainName $ member $ memberOf ) X-ORIGIN 'IPA v2' )
attributeTypes: (1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307bis' )
--
2.4.3
From 54883bca2cc73162994d8e8ba4140ece5185db49 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 7 Jul 2015 09:47:39 +0200
Subject: [PATCH 3/8] Added methods for setting time-based policies.
Methods for time-based policies in HBAC rules.
https://fedorahosted.org/freeipa/ticket/547
---
ACI.txt | 4 +-
API.txt | 50 ++++++-
freeipa.spec.in | 2 +
ipalib/__init__.py | 4 +-
ipalib/parameters.py | 180 -------------------------
ipalib/plugins/hbacrule.py | 330 +++++++++++++++++++++++++++++++--------------
6 files changed, 286 insertions(+), 284 deletions(-)
diff --git a/ACI.txt b/ACI.txt
index 40fa822217eaee8d0966491b10cdf7e0739a87ce..3372197d5b9a3ab2360df110ca4910a075b28a45 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -91,9 +91,9 @@ aci: (targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:Sy
dn: cn=hbac,dc=ipa,dc=example
aci: (targetattr = "externalhost || memberhost || memberservice || memberuser")(targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:System: Manage HBAC Rule Membership";allow (write) groupdn = "ldap:///cn=System: Manage HBAC Rule Membership,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=hbac,dc=ipa,dc=example
-aci: (targetattr = "accessruletype || accesstime || cn || description || hostcategory || ipaenabledflag || servicecategory || sourcehost || sourcehostcategory || usercategory")(targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:System: Modify HBAC Rule";allow (write) groupdn = "ldap:///cn=System: Modify HBAC Rule,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+aci: (targetattr = "accessruletype || accesstime || accesstimeexclude || cn || description || hostcategory || ipaenabledflag || ipatimezone || servicecategory || sourcehost || sourcehostcategory || usercategory")(targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:System: Modify HBAC Rule";allow (write) groupdn = "ldap:///cn=System: Modify HBAC Rule,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=hbac,dc=ipa,dc=example
-aci: (targetattr = "accessruletype || accesstime || cn || createtimestamp || description || entryusn || externalhost || hostcategory || ipaenabledflag || ipauniqueid || member || memberhost || memberservice || memberuser || modifytimestamp || objectclass || servicecategory || sourcehost || sourcehostcategory || usercategory")(targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:System: Read HBAC Rules";allow (compare,read,search) userdn = "ldap:///all";)
+aci: (targetattr = "accessruletype || accesstime || accesstimeexclude || cn || createtimestamp || description || entryusn || externalhost || hostcategory || ipaenabledflag || ipatimezone || ipauniqueid || member || memberhost || memberservice || memberuser || modifytimestamp || objectclass || servicecategory || sourcehost || sourcehostcategory || usercategory")(targetfilter = "(objectclass=ipahbacrule)")(version 3.0;acl "permission:System: Read HBAC Rules";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=hbacservices,cn=hbac,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipahbacservice)")(version 3.0;acl "permission:System: Add HBAC Services";allow (add) groupdn = "ldap:///cn=System: Add HBAC Services,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=hbacservices,cn=hbac,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index cf5446114a9ccffad8d87421b4cd75c92ff267ee..815320554c47d5da1ea208bb3d6abd4ddd1c5c43 100644
--- a/API.txt
+++ b/API.txt
@@ -1653,7 +1653,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: hbacrule_add
-args: 1,16,3
+args: 1,17,3
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, required=True)
option: StrEnum('accessruletype', attribute=True, autofill=True, cli_name='type', default=u'allow', exclude='webui', multivalue=False, required=True, values=(u'allow', u'deny'))
option: Str('addattr*', cli_name='addattr', exclude='webui')
@@ -1662,6 +1662,7 @@ option: Str('description', attribute=True, cli_name='desc', multivalue=False, re
option: Str('externalhost', attribute=True, cli_name='externalhost', multivalue=True, required=False)
option: StrEnum('hostcategory', attribute=True, cli_name='hostcat', multivalue=False, required=False, values=(u'all',))
option: Bool('ipaenabledflag', attribute=True, cli_name='ipaenabledflag', multivalue=False, required=False)
+option: Str('ipatimezone', attribute=True, cli_name='timezone', multivalue=False, required=False)
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: StrEnum('servicecategory', attribute=True, cli_name='servicecat', multivalue=False, required=False, values=(u'all',))
@@ -1674,6 +1675,28 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
+command: hbacrule_add_accesstime
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('accesstime', alwaysask=True, attribute=True, cli_name='time', multivalue=True, required=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: hbacrule_add_accesstimeexclude
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('accesstimeexclude', alwaysask=True, attribute=True, cli_name='excltime', multivalue=True, required=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
command: hbacrule_add_host
args: 1,6,3
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
@@ -1770,7 +1793,7 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('truncated', <type 'bool'>, None)
command: hbacrule_mod
-args: 1,18,3
+args: 1,19,3
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
option: StrEnum('accessruletype', attribute=True, autofill=False, cli_name='type', default=u'allow', exclude='webui', multivalue=False, required=False, values=(u'allow', u'deny'))
option: Str('addattr*', cli_name='addattr', exclude='webui')
@@ -1780,6 +1803,7 @@ option: Str('description', attribute=True, autofill=False, cli_name='desc', mult
option: Str('externalhost', attribute=True, autofill=False, cli_name='externalhost', multivalue=True, required=False)
option: StrEnum('hostcategory', attribute=True, autofill=False, cli_name='hostcat', multivalue=False, required=False, values=(u'all',))
option: Bool('ipaenabledflag', attribute=True, autofill=False, cli_name='ipaenabledflag', multivalue=False, required=False)
+option: Str('ipatimezone', attribute=True, autofill=False, cli_name='timezone', multivalue=False, required=False)
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Flag('rights', autofill=True, default=False)
@@ -1793,6 +1817,28 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
+command: hbacrule_remove_accesstime
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('accesstime', alwaysask=True, attribute=True, cli_name='time', multivalue=True, required=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: hbacrule_remove_accesstimeexclude
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('accesstimeexclude', alwaysask=True, attribute=True, cli_name='excltime', multivalue=True, required=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
command: hbacrule_remove_host
args: 1,6,3
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 38c76ce7f6f732f8731ff5f98de21f46d93998dd..087781623b74dc11432f28b54769df97155c2fb1 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -97,6 +97,7 @@ BuildRequires: python-pytest-multihost >= 0.5
BuildRequires: python-pytest-sourceorder
BuildRequires: python-kdcproxy >= 0.3
BuildRequires: python-six
+BuildRequires: pytz
%description
IPA is an integrated solution to provide centrally managed Identity (users,
@@ -322,6 +323,7 @@ Requires: wget
Requires: dbus-python
Requires: python-setuptools
Requires: python-six
+Requires: pytz
Conflicts: %{alt_name}-python
Obsoletes: %{alt_name}-python < %{version}
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index e163b292c075e21a8032261a13ca7ea5d6422830..be8db7269d93a62c92b11fa0c1d7ea5623d157af 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -886,8 +886,8 @@ from ipalib.frontend import Command, LocalOrRemote, Updater
from ipalib.frontend import Object, Method
from ipalib.crud import Create, Retrieve, Update, Delete, Search
from ipalib.parameters import DefaultFrom, Bool, Flag, Int, Decimal, Bytes, Str, IA5Str, Password, DNParam, DeprecatedParam
-from ipalib.parameters import (BytesEnum, StrEnum, IntEnum, AccessTime, File,
- DateTime, DNSNameParam)
+from ipalib.parameters import (BytesEnum, StrEnum, IntEnum, File,
+ DateTime, DNSNameParam)
from ipalib.errors import SkipPluginModule
from ipalib.text import _, ngettext, GettextFactory, NGettextFactory
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index dab235a2482f6707a813ad891d28d5e3a56e2e96..db6e4b5273ee6b76a471bdfa91d2f8ff45a89276 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -1670,186 +1670,6 @@ class DateTime(Param):
return super(DateTime, self)._convert_scalar(value, index)
-class AccessTime(Str):
- """
- Access time parameter type.
-
- Accepts values conforming to generalizedTime as defined in RFC 4517
- section 3.3.13 without time zone information.
- """
- def _check_HHMM(self, t):
- if len(t) != 4:
- raise ValueError('HHMM must be exactly 4 characters long')
- if not t.isnumeric():
- raise ValueError('HHMM non-numeric')
- hh = int(t[0:2])
- if hh < 0 or hh > 23:
- raise ValueError('HH out of range')
- mm = int(t[2:4])
- if mm < 0 or mm > 59:
- raise ValueError('MM out of range')
-
- def _check_dotw(self, t):
- if t.isnumeric():
- value = int(t)
- if value < 1 or value > 7:
- raise ValueError('day of the week out of range')
- elif t not in ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'):
- raise ValueError('invalid day of the week')
-
- def _check_dotm(self, t, month_num=1, year=4):
- if not t.isnumeric():
- raise ValueError('day of the month non-numeric')
- value = int(t)
- if month_num in (1, 3, 5, 7, 8, 10, 12):
- if value < 1 or value > 31:
- raise ValueError('day of the month out of range')
- elif month_num in (4, 6, 9, 11):
- if value < 1 or value > 30:
- raise ValueError('day of the month out of range')
- elif month_num == 2:
- if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
- if value < 1 or value > 29:
- raise ValueError('day of the month out of range')
- else:
- if value < 1 or value > 28:
- raise ValueError('day of the month out of range')
-
- def _check_wotm(self, t):
- if not t.isnumeric():
- raise ValueError('week of the month non-numeric')
- value = int(t)
- if value < 1 or value > 6:
- raise ValueError('week of the month out of range')
-
- def _check_woty(self, t):
- if not t.isnumeric():
- raise ValueError('week of the year non-numeric')
- value = int(t)
- if value < 1 or value > 52:
- raise ValueError('week of the year out of range')
-
- def _check_doty(self, t):
- if not t.isnumeric():
- raise ValueError('day of the year non-numeric')
- value = int(t)
- if value < 1 or value > 365:
- raise ValueError('day of the year out of range')
-
- def _check_month_num(self, t):
- if not t.isnumeric():
- raise ValueError('month number non-numeric')
- value = int(t)
- if value < 1 or value > 12:
- raise ValueError('month number out of range')
-
- def _check_interval(self, t, check_func):
- intervals = t.split(',')
- for i in intervals:
- if not i:
- raise ValueError('invalid time range')
- values = i.split('-')
- if len(values) > 2:
- raise ValueError('invalid time range')
- for v in values:
- check_func(v)
- if len(values) == 2:
- if int(values[0]) > int(values[1]):
- raise ValueError('invalid time range')
-
- def _check_W_spec(self, ts, index):
- if ts[index] != 'day':
- raise ValueError('invalid week specifier')
- index += 1
- self._check_interval(ts[index], self._check_dotw)
- return index
-
- def _check_M_spec(self, ts, index):
- if ts[index] == 'week':
- self._check_interval(ts[index + 1], self._check_wotm)
- index = self._check_W_spec(ts, index + 2)
- elif ts[index] == 'day':
- index += 1
- self._check_interval(ts[index], self._check_dotm)
- else:
- raise ValueError('invalid month specifier')
- return index
-
- def _check_Y_spec(self, ts, index):
- if ts[index] == 'month':
- index += 1
- self._check_interval(ts[index], self._check_month_num)
- month_num = int(ts[index])
- index = self._check_M_spec(ts, index + 1)
- elif ts[index] == 'week':
- self._check_interval(ts[index + 1], self._check_woty)
- index = self._check_W_spec(ts, index + 2)
- elif ts[index] == 'day':
- index += 1
- self._check_interval(ts[index], self._check_doty)
- else:
- raise ValueError('invalid year specifier')
- return index
-
- def _check_generalized(self, t):
- assert type(t) is unicode
- if len(t) not in (10, 12, 14):
- raise ValueError('incomplete generalized time')
- if not t.isnumeric():
- raise ValueError('time non-numeric')
- # don't check year value, with time travel and all :)
- self._check_month_num(t[4:6])
- year_num = int(t[0:4])
- month_num = int(t[4:6])
- self._check_dotm(t[6:8], month_num, year_num)
- if len(t) >= 12:
- self._check_HHMM(t[8:12])
- else:
- self._check_HHMM('%s00' % t[8:10])
- if len(t) == 14:
- s = int(t[12:14])
- if s < 0 or s > 60:
- raise ValueError('seconds out of range')
-
- def _check(self, time):
- ts = time.split()
- if ts[0] == 'absolute':
- if len(ts) != 4:
- raise ValueError('invalid format, must be \'absolute generalizedTime ~ generalizedTime\'')
- self._check_generalized(ts[1])
- if ts[2] != '~':
- raise ValueError('invalid time range separator')
- self._check_generalized(ts[3])
- if int(ts[1]) >= int(ts[3]):
- raise ValueError('invalid time range')
- elif ts[0] == 'periodic':
- index = None
- if ts[1] == 'yearly':
- index = self._check_Y_spec(ts, 2)
- elif ts[1] == 'monthly':
- index = self._check_M_spec(ts, 2)
- elif ts[1] == 'weekly':
- index = self._check_W_spec(ts, 2)
- elif ts[1] == 'daily':
- index = 1
- if index is None:
- raise ValueError('period must be yearly, monthy or daily, got \'%s\'' % ts[1])
- self._check_interval(ts[index + 1], self._check_HHMM)
- else:
- raise ValueError('time neither absolute or periodic')
-
- def _rule_required(self, _, value):
- try:
- self._check(value)
- except ValueError as e:
- raise ValidationError(name=self.get_param_name(), error=e.args[0])
- except IndexError:
- raise ValidationError(
- name=self.get_param_name(), error=ugettext('incomplete time value')
- )
- return None
-
-
class DNParam(Param):
type = DN
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 82a52bd80f58ede43249264db69acd193233448d..384016075f0618d159dc2cf27c60afcecc150daa 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -17,8 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from pytz import timezone, UnknownTimeZoneError
+
from ipalib import api, errors
-from ipalib import AccessTime, Password, Str, StrEnum, Bool, DeprecatedParam
+from ipalib import Password, Str, StrEnum, Bool, DeprecatedParam
from ipalib.plugable import Registry
from ipalib.plugins.baseldap import *
from ipalib import _, ngettext
@@ -34,6 +36,8 @@ You can also specify a category of users and target hosts.
This is currently limited to "all", but might be expanded in the
future.
+You can control the times when the rule is active, too.
+
Target hosts in HBAC rules must be hosts managed by IPA.
The available services and groups of services are controlled by the
@@ -69,25 +73,18 @@ EXAMPLES:
Remove a named HBAC rule:
ipa hbacrule-del allow_server
+
+ Specify that the rule "test1" should be active every day between 0800 and 1400:
+ ipa hbacrule-add-accesstime --time='timeofday=0800-1400' test1
+
+ Specify that the rule "test1" should be active once, from 10:32 until 10:33 on
+ December 16, 2010:
+ ipa hbacrule-add-accesstime --time='timeofday=1032-1033
+ dayofmonth=16 monthofyear=12 year=2010' test1
""")
register = Registry()
-# AccessTime support is being removed for now.
-#
-# You can also control the times that the rule is active.
-#
-# The access time(s) of a host are cumulative and are not guaranteed to be
-# applied in the order displayed.
-#
-# Specify that the rule "test1" be active every day between 0800 and 1400:
-# ipa hbacrule-add-accesstime --time='periodic daily 0800-1400' test1
-#
-# Specify that the rule "test1" be active once, from 10:32 until 10:33 on
-# December 16, 2010:
-# ipa hbacrule-add-accesstime --time='absolute 201012161032 ~ 201012161033' test1
-
-
topic = ('hbac', _('Host-based access control commands'))
def validate_type(ugettext, type):
@@ -109,6 +106,182 @@ def is_all(options, attribute):
return False
+# The following functions serve for validation of access time strings
+def _timearg_to_list(time):
+ '''
+ Parses the argument of either of the access time language keywords
+
+ Example: '1-5,12' into [[1,5], 12]
+ '''
+ return (t.split('-') for t in time.split(','))
+
+
+def _validate_range(keyword, lst, r1, r2, unit, unitlen):
+ '''
+ Checks the range of each keyword
+
+ keyword is the keyword string
+ lst is a list from _timearg_to_list,
+ r1 and r2 are the range borders for each keyword
+ unit is the unit of each keyword (e.g. day, year, ...)
+ unitlen is the maximum lenght of the argument (e.g. 2 for monthofyear
+ because max. month number is 12)
+ '''
+ for elempair in lst:
+ if(len(elempair) > 2):
+ return _('range may only consist of two numbers at once')
+ elold = 0
+ for i, elem in enumerate(elempair):
+ if not(elem):
+ # - or , used with no values -> got ''
+ return _('extra \'-\' or \',\'')
+ if len(elem) > unitlen:
+ return _('{kw} requires {unit} number {lb}-{rb}'
+ .format(kw=keyword, unit=unit, lb=r1, rb=r2))
+ if not(elem.isdigit()):
+ return _('{unit} in {kw} is not a number'
+ .format(unit=unit, kw=keyword))
+ elnum = int(elem)
+ if elnum < r1 or elnum > r2:
+ return _('{unit} in {kw} out of range. It needs '
+ 'number {lb}-{rb}'.format(unit=unit,
+ kw=keyword, lb=r1, rb=r2))
+ if not(i):
+ elold = elnum
+ elif elold > elnum:
+ return _('first part of {kw} range is greater than '
+ 'the second'.format(kw=keyword))
+
+
+def _validate_timeofday(t):
+ t = _timearg_to_list(t)
+
+ for time in t:
+ hhmmval = 0
+ for i, hhmm in enumerate(time):
+ if len(hhmm) != 4:
+ return _('timeofday requires time in HHMM format')
+ if not(hhmm.isdigit()):
+ return _('time in timeofday is not a number')
+ hours = int(hhmm[0:2])
+ minutes = int(hhmm[2:4])
+ if hours < 0 or hours > 23:
+ return _('hours value out of range')
+ if minutes < 0 or minutes > 59:
+ return _('minutes value out of range')
+ if not(i % 2):
+ hhmmval = hours*100 + minutes
+ elif hhmmval > (hours*100 + minutes):
+ return _('first part of timeofday range is greater than the second')
+
+
+def _validate_dayofweek(t):
+ t = _timearg_to_list(t)
+ return _validate_range('dayofweek', t, 1, 7, 'day', 1)
+
+
+def _validate_dayofmonth(t):
+ t = _timearg_to_list(t)
+ return _validate_range('dayofmonth', t, 1, 31, 'day', 2)
+
+
+def _validate_weekofmonth(t):
+ t = _timearg_to_list(t)
+ return _validate_range('weekofmonth', t, 0, 5, 'week', 1)
+
+
+def _validate_monthofyear(t):
+ t = _timearg_to_list(t)
+ return _validate_range('monthofyear', t, 1, 12, 'month', 2)
+
+
+def _validate_year(t):
+ t = _timearg_to_list(t)
+ return _validate_range('year', t, 1970, 9999, 'year', 4)
+
+
+def _validate_dayofyear(t):
+ t = _timearg_to_list(t)
+ return _validate_range('dayofyear', t, 1, 366, 'day', 3)
+
+
+def _validate_weekofyear(t):
+ t = _timearg_to_list(t)
+ return _validate_range('weekofyear', t, 0, 53, 'week', 2)
+
+
+def normalize_accesstime(t):
+ # multiple whitespaces to one
+ t = ' '.join(t.split())
+ t = t.lower()
+ # no spaces between intervals
+ t = re.sub(r'\s?,\s?', r',', t)
+ # no spaces around '=' sign
+ t = re.sub(r'\s?=\s?', r'=', t)
+ # no spaces around '-' sign
+ t = re.sub(r'\s?-\s?', r'-', t)
+ # if keyword=1234keyword make a space after 1234
+ t = re.sub(r'(\d)([a-zA-Z])', r'\1 \2', t)
+
+ return t
+
+
+def validate_accesstime(ugettext, value):
+ value = normalize_accesstime(value)
+ ts = value.split()
+ TOD, DOW, DOM, DOY, WOM, WOY, MOY, YEAR = range(0, 8)
+ found = [False] * (YEAR + 1)
+
+ res = None
+ for i, el in enumerate(ts):
+ if(el.startswith('timeofday=')):
+ res = _validate_timeofday(el[10:]) if not(found[TOD]) else \
+ _("multiple appearance of timeofday")
+ found[TOD] = True
+ elif(el.startswith('dayofweek=')):
+ res = _validate_dayofweek(el[10:]) if not(found[DOW]) else \
+ _("multiple appearance of dayofweek")
+ found[DOW] = True
+ elif(el.startswith('dayofmonth=')):
+ res = _validate_dayofmonth(el[11:]) if not(found[DOM]) else \
+ _("multiple appearance of dayofmonth")
+ found[DOM] = True
+ elif(el.startswith('dayofyear=')):
+ res = _validate_dayofyear(el[10:]) if not(found[DOY]) else \
+ _("multiple appearance of dayofyear")
+ found[DOY] = True
+ elif(el.startswith('weekofmonth=')):
+ res = _validate_weekofmonth(el[12:]) if not(found[WOM]) else \
+ _("multiple appearance of weekofmonth")
+ found[WOM] = True
+ elif(el.startswith('weekofyear=')):
+ res = _validate_weekofyear(el[11:]) if not(found[WOY]) else \
+ _("multiple appearance of weekofyear")
+ found[WOY] = True
+ elif(el.startswith('monthofyear=')):
+ res = _validate_monthofyear(el[12:]) if not(found[MOY]) else \
+ _("multiple appearance of monthofyear")
+ found[MOY] = True
+ elif(el.startswith('year=')):
+ res = _validate_year(el[5:]) if not(found[YEAR]) else \
+ _("multiple appearance of year")
+ found[YEAR] = True
+ else:
+ res = _('Unknown expression {exp} at position {pos}'
+ .format(exp=el, pos=i))
+ if res:
+ return res
+
+
+def validate_timezone(ugettext, value):
+ if value.lower() == 'host':
+ return
+ try:
+ timezone(value)
+ except UnknownTimeZoneError, e:
+ return _('Time zone unknown: {tz}'.format(tz=e.args[0]))
+
+
@register()
class hbacrule(LDAPObject):
"""
@@ -124,7 +297,8 @@ class hbacrule(LDAPObject):
'description', 'usercategory', 'hostcategory',
'servicecategory', 'ipaenabledflag',
'memberuser', 'sourcehost', 'memberhost', 'memberservice',
- 'externalhost',
+ 'memberhostgroup', 'externalhost', 'ipatimezone',
+ 'accesstime', 'accesstimeexclude'
]
uuid_attribute = 'ipauniqueid'
rdn_attribute = 'ipauniqueid'
@@ -140,7 +314,8 @@ class hbacrule(LDAPObject):
'ipapermbindruletype': 'all',
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
- 'accessruletype', 'accesstime', 'cn', 'description',
+ 'accessruletype', 'ipatimezone', 'accesstime',
+ 'accesstimeexclude', 'cn', 'description',
'externalhost', 'hostcategory', 'ipaenabledflag',
'ipauniqueid', 'memberhost', 'memberservice', 'memberuser',
'servicecategory', 'sourcehost', 'sourcehostcategory',
@@ -174,7 +349,8 @@ class hbacrule(LDAPObject):
'System: Modify HBAC Rule': {
'ipapermright': {'write'},
'ipapermdefaultattr': {
- 'accessruletype', 'accesstime', 'cn', 'description',
+ 'accessruletype', 'ipatimezone', 'accesstime',
+ 'accesstimeexclude', 'cn', 'description',
'hostcategory', 'ipaenabledflag', 'servicecategory',
'sourcehost', 'sourcehostcategory', 'usercategory'
},
@@ -224,10 +400,23 @@ class hbacrule(LDAPObject):
doc=_('Service category the rule applies to'),
values=(u'all', ),
),
-# AccessTime('accesstime?',
-# cli_name='time',
-# label=_('Access time'),
-# ),
+ Str('ipatimezone?', validate_timezone,
+ cli_name = 'timezone',
+ label = _('Time zone'),
+ flags = {'no_search'},
+ ),
+ Str('accesstime*', validate_accesstime,
+ cli_name='time',
+ label=_('Access time'),
+ flags = {'no_search', 'no_create', 'no_update'},
+ normalizer=normalize_accesstime,
+ ),
+ Str('accesstimeexclude*', validate_accesstime,
+ cli_name='excltime',
+ label=_('Access time exceptions'),
+ flags = {'no_search', 'no_create', 'no_update'},
+ normalizer=normalize_accesstime,
+ ),
Str('description?',
cli_name='desc',
label=_('Description'),
@@ -397,86 +586,32 @@ class hbacrule_disable(LDAPQuery):
)
+@register()
+class hbacrule_add_accesstime(LDAPAddAttribute):
+ __doc__ = _('Add allowed access times to an HBAC Rule')
+ msg_summary = _('Added allowed access times to the rule "%(value)s"')
+ attribute = 'accesstime'
-class hbacrule_add_accesstime(LDAPQuery):
- """
- Add an access time to an HBAC rule.
- """
- takes_options = (
- AccessTime('accesstime',
- cli_name='time',
- label=_('Access time'),
- ),
- )
+@register()
+class hbacrule_remove_accesstime(LDAPRemoveAttribute):
+ __doc__ = _('Remove access times from an HBAC Rule')
+ msg_summary = _('Removed access times from rule "%(value)s"')
+ attribute = 'accesstime'
- def execute(self, cn, **options):
- ldap = self.obj.backend
- dn = self.obj.get_dn(cn)
+@register()
+class hbacrule_add_accesstimeexclude(LDAPAddAttribute):
+ __doc__ = _('Add exceptions in access time to an HBAC Rule')
+ msg_summary = _('Added exceptions in access times to the rule "%(value)s"')
+ attribute = 'accesstimeexclude'
- entry_attrs = ldap.get_entry(dn, ['accesstime'])
- entry_attrs.setdefault('accesstime', []).append(
- options['accesstime']
- )
- try:
- ldap.update_entry(entry_attrs)
- except errors.EmptyModlist:
- pass
- except errors.NotFound:
- self.obj.handle_not_found(cn)
- return dict(result=True)
-
- def output_for_cli(self, textui, result, cn, **options):
- textui.print_name(self.name)
- textui.print_dashed(
- 'Added access time "%s" to HBAC rule "%s"' % (
- options['accesstime'], cn
- )
- )
-
-#api.register(hbacrule_add_accesstime)
-
-
-class hbacrule_remove_accesstime(LDAPQuery):
- """
- Remove access time to HBAC rule.
- """
- takes_options = (
- AccessTime('accesstime?',
- cli_name='time',
- label=_('Access time'),
- ),
- )
-
- def execute(self, cn, **options):
- ldap = self.obj.backend
-
- dn = self.obj.get_dn(cn)
-
- entry_attrs = ldap.get_entry(dn, ['accesstime'])
- try:
- entry_attrs.setdefault('accesstime', []).remove(
- options['accesstime']
- )
- ldap.update_entry(entry_attrs)
- except (ValueError, errors.EmptyModlist):
- pass
- except errors.NotFound:
- self.obj.handle_not_found(cn)
-
- return dict(result=True)
-
- def output_for_cli(self, textui, result, cn, **options):
- textui.print_name(self.name)
- textui.print_dashed(
- 'Removed access time "%s" from HBAC rule "%s"' % (
- options['accesstime'], cn
- )
- )
-
-#api.register(hbacrule_remove_accesstime)
+@register()
+class hbacrule_remove_accesstimeexclude(LDAPRemoveAttribute):
+ __doc__ = _('Remove exceptions in access times from an HBAC Rule')
+ msg_summary = _('Removed exceptions in access times from rule "%(value)s"')
+ attribute = 'accesstimeexclude'
@register()
@@ -593,4 +728,3 @@ class hbacrule_remove_service(LDAPRemoveMember):
member_attributes = ['memberservice']
member_count_out = ('%i object removed.', '%i objects removed.')
-
--
2.4.3
From a064527ebb271c349bffec546ff7f6bc04d25f24 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 11 Aug 2015 07:31:59 +0200
Subject: [PATCH 4/8] Added the "repeat" keyword.
The repeat keyword serves for setting recurrent events similar to
recurrent event rules in iCalendar.
https://fedorahosted.org/freeipa/ticket/547
---
ipalib/plugins/hbacrule.py | 116 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 112 insertions(+), 4 deletions(-)
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 384016075f0618d159dc2cf27c60afcecc150daa..779a75749dcb0bcdb6de6c22b6998be744b850c4 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from pytz import timezone, UnknownTimeZoneError
+from calendar import isleap
from ipalib import api, errors
from ipalib import Password, Str, StrEnum, Bool, DeprecatedParam
@@ -81,6 +82,16 @@ EXAMPLES:
December 16, 2010:
ipa hbacrule-add-accesstime --time='timeofday=1032-1033
dayofmonth=16 monthofyear=12 year=2010' test1
+ OR
+ ipa hbacrule-add-accesstime --time='timeofday=1032-1033
+ repeat=20101216+1d' test1
+
+ Specify that the rule "test1" should be active every Monday through Wednesday
+ and on Friday on the third week of every other month but not in February
+ starting October 3, 2015:
+ ipa hbacrule-add-accesstime --time='dayofweek=1-3,5 weekofmonth=3
+ repeat=20151003+2m' test1
+ ipa hbacrule-add-accesstimeexclude --excltime='monthofyear=2' test1
""")
register = Registry()
@@ -210,6 +221,95 @@ def _validate_weekofyear(t):
return _validate_range('weekofyear', t, 0, 53, 'week', 2)
+def _validate_ymd_range(y1, m1, d1, y2, m2, d2):
+ y1 = int(y1)
+ m1 = int(m1)
+ d1 = int(d1)
+ y2 = int(y2)
+ m2 = int(m2)
+ d2 = int(d2)
+
+ if y1 < y2:
+ return
+ elif y1 > y2:
+ return _("first year is greater than the second")
+ # y1 == y2
+ if m1 < m2:
+ return
+ elif m1 > m2:
+ return _("first month is greater than the second with equal years")
+ # y1 == y2 and m1 == m2
+ if d1 <= d2:
+ return
+ else:
+ return _("first day is greater than the second with equal "
+ "years and months")
+
+
+def _validate_date(y, m, d):
+ res = _validate_year(y)
+ if res:
+ return _("invalid year in date")
+ res = _validate_monthofyear(m)
+ if res:
+ return _("invalid month in year")
+ res = _validate_dayofmonth(d)
+ if res:
+ return _("invalid day in date")
+
+ year = int(y)
+ mon = int(m)
+ day = int(d)
+ if mon in (4, 6, 9, 11):
+ if day > 30:
+ return _("invalid day in date")
+
+ if mon == 2:
+ if isleap(year):
+ if day > 29:
+ return _("invalid day in date")
+ elif day > 28:
+ return _("invalid day in date")
+
+
+def _validate_repeat(t):
+ date1 = t[0:8]
+
+ y1 = date1[0:4]
+ m1 = date1[4:6]
+ d1 = date1[6:8]
+ res = _validate_date(y1, m1, d1)
+ if res:
+ return _("'repeat': ") + res
+
+ date2 = t[9:17] if t[8] == '-' else None
+ # control at pos 8 if there is no date2
+ ctlpos = 8
+ if date2:
+ y2 = date2[0:4]
+ m2 = date2[4:6]
+ d2 = date2[6:8]
+ res = _validate_date(y2, m2, d2)
+ if res:
+ return _("'repeat': ") + res
+
+ res = _validate_ymd_range(y1, m1, d1, y2, m2, d2)
+ if res:
+ return _("'repeat': ") + res
+
+ ctlpos = 17
+
+ if t[ctlpos] != '+':
+ return _("'repeat': wrong syntax, '+' expected")
+ ctlpos += 1
+ if not('1' <= t[ctlpos] <= '9'):
+ return _("'repeat': wrong syntax, expected a number after '+'")
+ while t[ctlpos].isdigit():
+ ctlpos += 1
+ if t[ctlpos] not in ('d', 'w', 'm', 'y'):
+ return _("'repeat': wrong syntax, d/w/m/y expected")
+
+
def normalize_accesstime(t):
# multiple whitespaces to one
t = ' '.join(t.split())
@@ -221,16 +321,20 @@ def normalize_accesstime(t):
# no spaces around '-' sign
t = re.sub(r'\s?-\s?', r'-', t)
# if keyword=1234keyword make a space after 1234
- t = re.sub(r'(\d)([a-zA-Z])', r'\1 \2', t)
-
+ # don't make space after num in range=... (that's why {2})
+ t = re.sub(r'(\d)([a-z]{2})', r'\1 \2', t)
+ # no spaces around '+' in repeat
+ t = re.sub(r'\s+\s', r'+', t)
+ # no spaces after interval number in repeat
+ t = re.sub(r'(\d)\s(d|w|m|y)\s', r'\1\2', t)
return t
def validate_accesstime(ugettext, value):
value = normalize_accesstime(value)
ts = value.split()
- TOD, DOW, DOM, DOY, WOM, WOY, MOY, YEAR = range(0, 8)
- found = [False] * (YEAR + 1)
+ TOD, DOW, DOM, DOY, WOM, WOY, MOY, YEAR, RPT = range(0, 9)
+ found = [False] * (RPT + 1)
res = None
for i, el in enumerate(ts):
@@ -266,6 +370,10 @@ def validate_accesstime(ugettext, value):
res = _validate_year(el[5:]) if not(found[YEAR]) else \
_("multiple appearance of year")
found[YEAR] = True
+ elif(el.startswith('repeat=')):
+ res = _validate_repeat(el[7:]) if not(found[RPT]) else \
+ _("multiple appearance of repeat")
+ found[RPT] = True
else:
res = _('Unknown expression {exp} at position {pos}'
.format(exp=el, pos=i))
--
2.4.3
From b8915c92389675e985f5bc29de9f3ee78b0c5ae4 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 1 Sep 2015 15:42:19 +0200
Subject: [PATCH 5/8] HBAC test module support for time-based policies
https://fedorahosted.org/freeipa/ticket/547
---
API.txt | 3 ++-
ipalib/plugins/hbactest.py | 22 +++++++++++++++++++++-
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/API.txt b/API.txt
index 815320554c47d5da1ea208bb3d6abd4ddd1c5c43..1cd3456be5c820fb1efd0c2059a5a537e46a6e3e 100644
--- a/API.txt
+++ b/API.txt
@@ -2047,9 +2047,10 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: hbactest
-args: 0,10,6
+args: 0,11,6
option: Flag('disabled?', autofill=True, cli_name='disabled', default=False)
option: Flag('enabled?', autofill=True, cli_name='enabled', default=False)
+option: Str('hosttimezone?', cli_name='timezone')
option: Flag('nodetail?', autofill=True, cli_name='nodetail', default=False)
option: Str('rules*', cli_name='rules', csv=True)
option: Str('service', cli_name='service')
diff --git a/ipalib/plugins/hbactest.py b/ipalib/plugins/hbactest.py
index b528707f785c711ce6449237ea789d56cda2dcbb..9ace736c3b0d5ea2792a4b9636729ddab60a2f3b 100644
--- a/ipalib/plugins/hbactest.py
+++ b/ipalib/plugins/hbactest.py
@@ -24,6 +24,7 @@ from ipalib.cli import to_cli
from ipalib import _, ngettext
from ipapython.dn import DN
from ipalib.plugable import Registry
+from ipalib.plugins.hbacrule import validate_timezone
if api.env.in_server and api.env.context in ['lite', 'server']:
try:
import ipaserver.dcerpc
@@ -31,6 +32,7 @@ if api.env.in_server and api.env.context in ['lite', 'server']:
except ImportError:
_dcerpc_bindings_installed = False
+import time
import pyhbac
import six
@@ -239,6 +241,12 @@ def convert_to_ipa_rule(rule):
attr_name = '%s_%s' % (element[1], element[3])
if attr_name in rule:
element[4].groups = rule[attr_name]
+ if 'ipatimezone' in rule:
+ ipa_rule.timerules.timezone = rule['ipatimezone'][0]
+ if 'accesstime' in rule:
+ ipa_rule.timerules.accesstimes = rule['accesstime']
+ if 'accesstimeexclude' in rule:
+ ipa_rule.timerules.exceptions = rule['accesstimeexclude']
if 'externalhost' in rule:
ipa_rule.srchosts.names.extend(rule['externalhost']) #pylint: disable=E1101
return ipa_rule
@@ -268,6 +276,10 @@ class hbactest(Command):
cli_name='host',
label=_('Target host'),
),
+ Str('hosttimezone?', validate_timezone,
+ cli_name='timezone',
+ label=_('Host\'s time zone'),
+ ),
Str('service',
cli_name='service',
label=_('Service'),
@@ -375,6 +387,7 @@ class hbactest(Command):
# Rules are converted to pyhbac format, build request and then test it
request = pyhbac.HbacRequest()
+ request.req_time = int(time.time())
if options['user'] != u'all':
# check first if this is not a trusted domain user
@@ -457,6 +470,14 @@ class hbactest(Command):
warning_rules = []
result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None}
+
+ if 'hosttimezone' in options:
+ # The 'host' time zone settings needs to be changed
+ # If 'hosttimezone' is not set, leave it to local time zone
+ for ipa_rule in rules:
+ if ipa_rule.timerules.timezone.lower() == 'host':
+ ipa_rule.timerules.timezone = options['hosttimezone']
+
if not options['nodetail']:
# Validate runs rules one-by-one and reports failed ones
for ipa_rule in rules:
@@ -518,4 +539,3 @@ class hbactest(Command):
# Propagate integer value for result. It will give proper command line result for scripts
return int(not output['value'])
-
--
2.4.3
From fae365648324f80e3fea9dbc08d2c4ab9e908727 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 2 Sep 2015 11:50:14 +0200
Subject: [PATCH 6/8] Removed old AccessTime parameter tests.
https://fedorahosted.org/freeipa/ticket/547
---
ipatests/test_ipalib/test_parameters.py | 39 ---------------------------------
1 file changed, 39 deletions(-)
diff --git a/ipatests/test_ipalib/test_parameters.py b/ipatests/test_ipalib/test_parameters.py
index 929289258ca2ff02f78900bfcc91d701ab276898..fe3ab7b042f0f7dfb23b7907c8023d47b1194fd3 100644
--- a/ipatests/test_ipalib/test_parameters.py
+++ b/ipatests/test_ipalib/test_parameters.py
@@ -1487,45 +1487,6 @@ class test_Decimal(ClassChecker):
else:
param(value)
-class test_AccessTime(ClassChecker):
- """
- Test the `ipalib.parameters.AccessTime` class.
- """
- _cls = parameters.AccessTime
-
- def test_init(self):
- """
- Test the `ipalib.parameters.AccessTime.__init__` method.
- """
- # Test with no kwargs:
- o = self.cls('my_time')
- assert o.type is unicode
- assert isinstance(o, parameters.AccessTime)
- assert o.multivalue is False
- translation = u'length=%(length)r'
- dummy = dummy_ugettext(translation)
- assert dummy.translation is translation
- rule = o._rule_required
-
- # Check some good rules
- for value in (u'absolute 201012161032 ~ 201012161033',
- u'periodic monthly week 2 day Sat,Sun 0900-1300',
- u'periodic yearly month 4 day 1-31 0800-1400',
- u'periodic weekly day 7 0800-1400',
- u'periodic daily 0800-1400',
- ):
- assert rule(dummy, value) is None
- assert dummy.called() is False
-
- # And some bad ones
- for value in (u'absolute 201012161032 - 201012161033',
- u'absolute 201012161032 ~',
- u'periodic monthly day Sat,Sun 0900-1300',
- u'periodical yearly month 4 day 1-31 0800-1400',
- u'periodic weekly day 8 0800-1400',
- ):
- e = raises(ValidationError, o._rule_required, None, value)
-
def test_create_param():
"""
Test the `ipalib.parameters.create_param` function.
--
2.4.3
From b729c720bd7e9d5c003cf15148d05ac8ef80a72e Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Thu, 3 Sep 2015 09:48:04 +0200
Subject: [PATCH 7/8] Tests for HBAC time rules language
https://fedorahosted.org/freeipa/ticket/547
---
ipatests/test_xmlrpc/test_hbac_plugin.py | 205 +++++++++++++++++++++++----
ipatests/test_xmlrpc/test_hbactest_plugin.py | 4 +-
2 files changed, 180 insertions(+), 29 deletions(-)
diff --git a/ipatests/test_xmlrpc/test_hbac_plugin.py b/ipatests/test_xmlrpc/test_hbac_plugin.py
index a9677bfdebecd8eaa746640834e067832d516728..5b259d879f15fee8d3eaba9db66e116b15357165 100644
--- a/ipatests/test_xmlrpc/test_hbac_plugin.py
+++ b/ipatests/test_xmlrpc/test_hbac_plugin.py
@@ -34,10 +34,11 @@ class test_hbac(XMLRPC_test):
rule_type = u'allow'
rule_type_fail = u'value not allowed'
rule_service = u'ssh'
- rule_time = u'absolute 20081010000000 ~ 20081015120000'
- rule_time2 = u'absolute 20081010000000 ~ 20081016120000'
- # wrong time, has 30th day in February in first date
- rule_time_fail = u'absolute 20080230000000 ~ 20081015120000'
+ rule_time = u'timeofday=0000-2359 dayofmonth=1-15,16-31 ' \
+ 'dayofyear=23-47,26-77 year=1970-2563'
+ rule_time2 = u'weekofmonth=0,1,4,5 monthofyear=1-3,7,9,11-12 ' \
+ 'repeat=20150522-20150630+12d'
+ rule_time3 = u'timeofday=0700-1600 dayofmonth=1,3,5,22 repeat=19980217+4w'
rule_desc = u'description'
rule_desc_mod = u'description modified'
@@ -93,30 +94,178 @@ class test_hbac(XMLRPC_test):
entry = ret['result']
assert_attr_equal(entry, 'description', self.rule_desc_mod)
-# def test_4_hbacrule_add_accesstime(self):
-# """
-# Test adding access time to HBAC rule using `xmlrpc.hbacrule_add_accesstime`.
-# """
-# return
-# ret = api.Command['hbacrule_add_accesstime'](
-# self.rule_name, accesstime=self.rule_time2
-# )
-# entry = ret['result']
-# assert_attr_equal(entry, 'accesstime', self.rule_time);
-# assert_attr_equal(entry, 'accesstime', self.rule_time2);
-
-# def test_5_hbacrule_add_accesstime(self):
-# """
-# Test adding invalid access time to HBAC rule using `xmlrpc.hbacrule_add_accesstime`.
-# """
-# try:
-# api.Command['hbacrule_add_accesstime'](
-# self.rule_name, accesstime=self.rule_time_fail
-# )
-# except errors.ValidationError:
-# pass
-# else:
-# assert False
+ def test_4_hbacrule_add_accesstime(self):
+ """
+ Test adding access time to HBAC rule using `xmlrpc.hbacrule_add_accesstime`.
+ """
+ ret = api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=(self.rule_time, self.rule_time2,
+ self.rule_time3)
+ )
+ entry = ret['result']
+ assert_attr_equal(entry, 'accesstime', self.rule_time)
+ assert_attr_equal(entry, 'accesstime', self.rule_time2)
+ assert_attr_equal(entry, 'accesstime', self.rule_time3)
+
+ @raises(errors.ValidationError)
+ def test_5_hbacrule_add_accesstime(self):
+ """
+ This and the following add_accesstime tests test adding invalid access
+ times to HBAC rule using `xmlrpc.hbacrule_add_accesstime`.
+ """
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'nonsense'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_TOD_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'timeofday=2400'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_TOD_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'timeofday=1060'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_TOD_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'timeofday=7800'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOW_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofweek=57'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOW_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofweek=0'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOW_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofweek=8'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOM_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofmonth=280'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOM_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofmonth=0'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOM_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofmonth=32'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_WOM_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'weekofmonth=350'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_WOM_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'weekofmonth=6'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_MOY_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'monthofyear=789'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_MOY_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'monthofyear=0'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_MOY_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'monthofyear=13'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_YEAR_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'year=235'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_YEAR_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'year=1969'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_YEAR_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'year=10000'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOY_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofyear=48646'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOY_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofyear=0'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_DOY_3(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'dayofyear=367'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_WOY_1(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'weekofyear=6879754'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_WOY_2(self):
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'weekofyear=54'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_RPT_1(self):
+ """
+ Test invalid day of month
+ """
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'repeat=20150631+1d'
+ )
+
+ @raises(errors.ValidationError)
+ def test_hbacrule_add_accesstime_RPT_2(self):
+ """
+ Test second date lower than first
+ """
+ api.Command['hbacrule_add_accesstime'](
+ self.rule_name, accesstime=u'repeat=20150630-20150629+1d'
+ )
def test_6_hbacrule_find(self):
"""
diff --git a/ipatests/test_xmlrpc/test_hbactest_plugin.py b/ipatests/test_xmlrpc/test_hbactest_plugin.py
index 6f7b0a6155fafa3eea5b870e49c3633bd0b48046..5d79d168e76c72b9b3794868dc1caf2aa4f67500 100644
--- a/ipatests/test_xmlrpc/test_hbactest_plugin.py
+++ b/ipatests/test_xmlrpc/test_hbactest_plugin.py
@@ -48,6 +48,7 @@ class test_hbactest(XMLRPC_test):
test_sourcehost = u'hbacrule.testsrchost'
test_sourcehostgroup = u'hbacrule_test_src_hostgroup'
test_service = u'ssh'
+ test_timezone = u'America/Argentina/San_Juan'
# Auxiliary funcion for checking existence of warning for specified rule
def check_rule_presence(self,rule_name,warnings):
@@ -111,6 +112,7 @@ class test_hbactest(XMLRPC_test):
user=self.test_user,
targethost=self.test_host,
service=self.test_service,
+ hosttimezone=self.test_timezone,
rules=self.rule_names
)
assert ret['value'] == True
@@ -126,6 +128,7 @@ class test_hbactest(XMLRPC_test):
user=self.test_user,
targethost=self.test_host,
service=self.test_service,
+ hosttimezone=self.test_timezone,
rules=self.rule_names,
nodetail=True
)
@@ -214,4 +217,3 @@ class test_hbactest(XMLRPC_test):
api.Command['host_del'](self.test_sourcehost)
api.Command['hostgroup_del'](self.test_sourcehostgroup)
api.Command['hbacsvc_del'](self.test_service)
-
--
2.4.3
From 31eb7e5aacbd879432065d83fb0c5c126042d957 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 30 Sep 2015 12:42:19 +0200
Subject: [PATCH 8/8] Added negative values to the HBAC time policies
https://fedorahosted.org/freeipa/ticket/547
---
ipalib/plugins/hbacrule.py | 71 ++++++++++++++++++++++++--------
ipatests/test_xmlrpc/test_hbac_plugin.py | 15 ++++---
2 files changed, 62 insertions(+), 24 deletions(-)
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 779a75749dcb0bcdb6de6c22b6998be744b850c4..66c587030d67608ee91b7d904cf115cabb742680 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -76,20 +76,20 @@ EXAMPLES:
ipa hbacrule-del allow_server
Specify that the rule "test1" should be active every day between 0800 and 1400:
- ipa hbacrule-add-accesstime --time='timeofday=0800-1400' test1
+ ipa hbacrule-add-accesstime --time='timeofday=0800~1400' test1
Specify that the rule "test1" should be active once, from 10:32 until 10:33 on
December 16, 2010:
- ipa hbacrule-add-accesstime --time='timeofday=1032-1033
+ ipa hbacrule-add-accesstime --time='timeofday=1032~1033
dayofmonth=16 monthofyear=12 year=2010' test1
OR
- ipa hbacrule-add-accesstime --time='timeofday=1032-1033
+ ipa hbacrule-add-accesstime --time='timeofday=1032~1033
repeat=20101216+1d' test1
Specify that the rule "test1" should be active every Monday through Wednesday
and on Friday on the third week of every other month but not in February
starting October 3, 2015:
- ipa hbacrule-add-accesstime --time='dayofweek=1-3,5 weekofmonth=3
+ ipa hbacrule-add-accesstime --time='dayofweek=1~3,5 weekofmonth=3
repeat=20151003+2m' test1
ipa hbacrule-add-accesstimeexclude --excltime='monthofyear=2' test1
""")
@@ -122,12 +122,12 @@ def _timearg_to_list(time):
'''
Parses the argument of either of the access time language keywords
- Example: '1-5,12' into [[1,5], 12]
+ Example: '1~5,12' into [[1,5], 12]
'''
- return (t.split('-') for t in time.split(','))
+ return (t.split('~') for t in time.split(','))
-def _validate_range(keyword, lst, r1, r2, unit, unitlen):
+def _validate_range(keyword, lst, r1, r2, unit, unitlen, loose=0):
'''
Checks the range of each keyword
@@ -137,15 +137,22 @@ def _validate_range(keyword, lst, r1, r2, unit, unitlen):
unit is the unit of each keyword (e.g. day, year, ...)
unitlen is the maximum lenght of the argument (e.g. 2 for monthofyear
because max. month number is 12)
+ loose allows looser evaluation when there is a first negative value in
+ a range. This helps in cases e.g. for dayofmonth -28~1 vs. -31~1 where
+ there are multiple higher borders possible.
'''
for elempair in lst:
if(len(elempair) > 2):
return _('range may only consist of two numbers at once')
elold = 0
+ neg = [False, False]
for i, elem in enumerate(elempair):
if not(elem):
- # - or , used with no values -> got ''
- return _('extra \'-\' or \',\'')
+ # ~ or , used with no values -> got ''
+ return _('extra \'~\' or \',\'')
+ if elem[0] == '-' and keyword != 'year':
+ elem = elem[1:]
+ neg[i] = True
if len(elem) > unitlen:
return _('{kw} requires {unit} number {lb}-{rb}'
.format(kw=keyword, unit=unit, lb=r1, rb=r2))
@@ -153,12 +160,38 @@ def _validate_range(keyword, lst, r1, r2, unit, unitlen):
return _('{unit} in {kw} is not a number'
.format(unit=unit, kw=keyword))
elnum = int(elem)
- if elnum < r1 or elnum > r2:
- return _('{unit} in {kw} out of range. It needs '
- 'number {lb}-{rb}'.format(unit=unit,
- kw=keyword, lb=r1, rb=r2))
+ if keyword == 'weekofmonth' and neg[i]:
+ if elnum == 0:
+ return _('negative zero is not allowed')
+ if elnum < r1 or elnum > (r2+1):
+ return _('{unit} in {kw} out of range. It needs '
+ 'negative number in range from -{lb} to -{rb}'
+ .format(unit=unit, kw=keyword, lb=r1, rb=r2+1))
+ else:
+ if elnum < r1 or elnum > r2:
+ return _('{unit} in {kw} out of range. It needs '
+ 'number {lb}-{rb}'
+ .format(unit=unit, kw=keyword, lb=r1, rb=r2))
+
if not(i):
elold = elnum
+ elif True in neg:
+ if neg[0] == neg[1]:
+ if elold < elnum:
+ return _('first negative part of {kw} range makes '
+ 'higher value than the second part'
+ .format(kw=keyword))
+ elif neg[0]:
+ if (r2 - elold + 1) > (elnum + loose):
+ return _('first part of {kw} range makes higher value '
+ 'than the second part'
+ .format(kw=keyword))
+ else:
+ #the second part is negative
+ if (elold + elnum - 1) > r2:
+ return _('first part of {kw} range is higher than the '
+ 'second'
+ .format(kw=keyword))
elif elold > elnum:
return _('first part of {kw} range is greater than '
'the second'.format(kw=keyword))
@@ -193,12 +226,12 @@ def _validate_dayofweek(t):
def _validate_dayofmonth(t):
t = _timearg_to_list(t)
- return _validate_range('dayofmonth', t, 1, 31, 'day', 2)
+ return _validate_range('dayofmonth', t, 1, 31, 'day', 2, 3)
def _validate_weekofmonth(t):
t = _timearg_to_list(t)
- return _validate_range('weekofmonth', t, 0, 5, 'week', 1)
+ return _validate_range('weekofmonth', t, 0, 5, 'week', 1, 1)
def _validate_monthofyear(t):
@@ -213,12 +246,12 @@ def _validate_year(t):
def _validate_dayofyear(t):
t = _timearg_to_list(t)
- return _validate_range('dayofyear', t, 1, 366, 'day', 3)
+ return _validate_range('dayofyear', t, 1, 366, 'day', 3, 1)
def _validate_weekofyear(t):
t = _timearg_to_list(t)
- return _validate_range('weekofyear', t, 0, 53, 'week', 2)
+ return _validate_range('weekofyear', t, 0, 53, 'week', 2, 1)
def _validate_ymd_range(y1, m1, d1, y2, m2, d2):
@@ -282,7 +315,7 @@ def _validate_repeat(t):
if res:
return _("'repeat': ") + res
- date2 = t[9:17] if t[8] == '-' else None
+ date2 = t[9:17] if t[8] == '~' else None
# control at pos 8 if there is no date2
ctlpos = 8
if date2:
@@ -320,6 +353,8 @@ def normalize_accesstime(t):
t = re.sub(r'\s?=\s?', r'=', t)
# no spaces around '-' sign
t = re.sub(r'\s?-\s?', r'-', t)
+ # no spaces around - sign
+ t = re.sub(r'\s?~\s?', r'~', t)
# if keyword=1234keyword make a space after 1234
# don't make space after num in range=... (that's why {2})
t = re.sub(r'(\d)([a-z]{2})', r'\1 \2', t)
diff --git a/ipatests/test_xmlrpc/test_hbac_plugin.py b/ipatests/test_xmlrpc/test_hbac_plugin.py
index 5b259d879f15fee8d3eaba9db66e116b15357165..973252ba51a874b5a5cb2562a4496ec71bf8fb2f 100644
--- a/ipatests/test_xmlrpc/test_hbac_plugin.py
+++ b/ipatests/test_xmlrpc/test_hbac_plugin.py
@@ -34,11 +34,13 @@ class test_hbac(XMLRPC_test):
rule_type = u'allow'
rule_type_fail = u'value not allowed'
rule_service = u'ssh'
- rule_time = u'timeofday=0000-2359 dayofmonth=1-15,16-31 ' \
- 'dayofyear=23-47,26-77 year=1970-2563'
- rule_time2 = u'weekofmonth=0,1,4,5 monthofyear=1-3,7,9,11-12 ' \
- 'repeat=20150522-20150630+12d'
- rule_time3 = u'timeofday=0700-1600 dayofmonth=1,3,5,22 repeat=19980217+4w'
+ rule_time = u'timeofday=0000~2359 dayofmonth=1~15,16~31 ' \
+ 'dayofyear=23~47,26~77 year=1970~2563'
+ rule_time2 = u'weekofmonth=0,1,4,5 monthofyear=1~3,7,9,11~12 ' \
+ 'repeat=20150522~20150630+12d'
+ rule_time3 = u'timeofday=0700~1600 dayofmonth=1,3,5,22 repeat=19980217+4w'
+ rule_time_neg = u'timeofday=2237~2352 monthofyear=1~3,-7~-1 ' \
+ 'dayofmonth=-25~-12,-15~-7,5~17,-5~-2 year=1973'
rule_desc = u'description'
rule_desc_mod = u'description modified'
@@ -100,12 +102,13 @@ class test_hbac(XMLRPC_test):
"""
ret = api.Command['hbacrule_add_accesstime'](
self.rule_name, accesstime=(self.rule_time, self.rule_time2,
- self.rule_time3)
+ self.rule_time3, self.rule_time_neg)
)
entry = ret['result']
assert_attr_equal(entry, 'accesstime', self.rule_time)
assert_attr_equal(entry, 'accesstime', self.rule_time2)
assert_attr_equal(entry, 'accesstime', self.rule_time3)
+ assert_attr_equal(entry, 'accesstime', self.rule_time_neg)
@raises(errors.ValidationError)
def test_5_hbacrule_add_accesstime(self):
--
2.4.3
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code