On Mon, 2014-05-05 at 12:42 -0400, Nathaniel McCallum wrote:
> This also constitutes a rethinking of the token ACIs after the
> introduction of SELFDN support.
> 
> Admins, as before, have full access to all token permissions.
> 
> Normal users have read/search/compare access to all of the non-secret
> data for tokens assigned to them, whether protected or non-protected.
> Users can add or delete non-protected tokens and modify most of their
> metadata. However they cannot create, delete or modify protected tokens.
> Regardless of whether the token is protected or not, users cannot change
> a token's ownership or unique identity.
> 
> In contrast, admins can create protected tokens. This protects the token
> from deletion or modification when assigned to users. Additionally, when
> a user account is deleted, the assigned non-protected tokens are deleted
> but the protected tokens are merely orphaned. This permits the token to
> be reassigned without having to recreate it. This last point is
> particularly useful in the case of hardware tokens.
> 
> https://fedorahosted.org/freeipa/ticket/4228
> 
> NOTE: This patch depends on my patch 0048.

This new version makes ipatokenDisabled visible for token owners. It is
also writable if the token is non-protected. This additionally fixes:

https://fedorahosted.org/freeipa/ticket/4259

Nathaniel
>From 4340378d134e294d8c9e74673f9302d59f76a779 Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccal...@redhat.com>
Date: Fri, 2 May 2014 16:44:30 -0400
Subject: [PATCH] Add support for protected tokens

This also constitutes a rethinking of the token ACIs after the introduction
of SELFDN support.

Admins, as before, have full access to all token permissions.

Normal users have read/search/compare access to all of the non-secret data
for tokens assigned to them, whether protected or non-protected. Users can
add or delete non-protected tokens and modify most of their metadata.
However they cannot create, delete or modify protected tokens. Regardless
of whether the token is protected or not, users cannot change a token's
ownership or unique identity.

In contrast, admins can create protected tokens. This protects the token
from deletion or modification when assigned to users. Additionally, when
a user account is deleted, the assigned non-protected tokens are deleted
but the protected tokens are merely orphaned. This permits the token to
be reassigned without having to recreate it. This last point is
particularly useful in the case of hardware tokens.

https://fedorahosted.org/freeipa/ticket/4228
https://fedorahosted.org/freeipa/ticket/4259
---
 install/share/70ipaotp.ldif    |  3 ++-
 install/share/default-aci.ldif | 10 +++++-----
 install/updates/40-otp.update  | 16 +++++++++++-----
 ipalib/plugins/otptoken.py     |  9 +++++++++
 ipalib/plugins/user.py         |  9 ++++++++-
 5 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/install/share/70ipaotp.ldif b/install/share/70ipaotp.ldif
index a40ad9ee0cfcf72ed6b79306396a29683f9e1a9d..08f639b6cd14b6dd1270a604fdd061cecb4a6482 100644
--- a/install/share/70ipaotp.ldif
+++ b/install/share/70ipaotp.ldif
@@ -23,7 +23,8 @@ attributeTypes: (2.16.840.1.113730.3.8.16.1.18 NAME 'ipatokenRadiusTimeout' DESC
 attributeTypes: (2.16.840.1.113730.3.8.16.1.19 NAME 'ipatokenRadiusRetries' DESC 'Number of allowed Retries' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP')
 attributeTypes: (2.16.840.1.113730.3.8.16.1.20 NAME 'ipatokenUserMapAttribute' DESC 'Attribute to map from the user entry for RADIUS server authentication' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP')
 attributeTypes: (2.16.840.1.113730.3.8.16.1.21 NAME 'ipatokenHOTPcounter' DESC 'HOTP counter' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP')
-objectClasses:  (2.16.840.1.113730.3.8.16.2.1  NAME 'ipaToken' SUP top ABSTRACT DESC 'Abstract token class for tokens' MUST (ipatokenUniqueID) MAY (description $ ipatokenOwner $ ipatokenDisabled $ ipatokenNotBefore $ ipatokenNotAfter $ ipatokenVendor $ ipatokenModel $ ipatokenSerial) X-ORIGIN 'IPA OTP')
+attributeTypes: (2.16.840.1.113730.3.8.16.1.22 NAME 'ipatokenProtected' DESC 'Optionally marks token as Protected' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA OTP')
+objectClasses:  (2.16.840.1.113730.3.8.16.2.1  NAME 'ipaToken' SUP top ABSTRACT DESC 'Abstract token class for tokens' MUST (ipatokenUniqueID) MAY (description $ ipatokenOwner $ ipatokenDisabled $ ipatokenNotBefore $ ipatokenNotAfter $ ipatokenVendor $ ipatokenModel $ ipatokenSerial $ ipatokenProtected) X-ORIGIN 'IPA OTP')
 objectClasses:  (2.16.840.1.113730.3.8.16.2.2  NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MUST (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenTOTPclockOffset $ ipatokenTOTPtimeStep) X-ORIGIN 'IPA OTP')
 objectClasses:  (2.16.840.1.113730.3.8.16.2.3  NAME 'ipatokenRadiusProxyUser' SUP top AUXILIARY DESC 'Radius Proxy User' MAY (ipatokenRadiusConfigLink $ ipatokenRadiusUserName) X-ORIGIN 'IPA OTP')
 objectClasses:  (2.16.840.1.113730.3.8.16.2.4  NAME 'ipatokenRadiusConfiguration' SUP top STRUCTURAL DESC 'Proxy Radius Configuration' MUST (cn $ ipatokenRadiusServer $ ipatokenRadiusSecret) MAY (description $ ipatokenRadiusTimeout $ ipatokenRadiusRetries $ ipatokenUserMapAttribute) X-ORIGIN 'IPA OTP')
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index 480facf3294c593c6a2bcf326e20c32157d6d3c6..c7872523ca1b1afb46fe9f09d62218c08033469a 100644
--- a/install/share/default-aci.ldif
+++ b/install/share/default-aci.ldif
@@ -97,8 +97,8 @@ aci: (target="ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX";)(targetattr="use
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)
-aci: (targetfilter = "(objectClass=ipaToken)")(targetattrs = "ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)
-aci: (targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPclockOffset || ipatokenTOTPtimeStep")(version 3.0; acl "Users can add TOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)
-aci: (target = "ldap:///ipatokenuniqueid=*,cn=otp,$SUFFIX";)(targetfilter = "(objectClass=ipaToken)")(version 3.0; acl "Users can create and delete tokens"; allow (add, delete) userattr = "ipatokenOwner#SELFDN";)
-aci: (targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenHOTPcounter")(version 3.0; acl "Users can add HOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)
+aci: (targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || description || ipatokenUniqueID || ipatokenDisabled || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial || ipatokenOwner || ipatokenProtected")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)
+aci: (targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPtimeStep")(version 3.0; acl "Users can see TOTP details"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)
+aci: (targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPalgorithm || ipatokenOTPdigits")(version 3.0; acl "Users can see HOTP details"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)
+aci: (targetfilter = "(&(objectClass=ipaToken)(!(ipatokenProtected=TRUE)))")(targetattrs = "description || ipatokenDisabled || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)
+aci: (target = "ldap:///ipatokenuniqueid=*,cn=otp,$SUFFIX";)(targetfilter = "(&(objectClass=ipaToken)(!(ipatokenProtected=TRUE))))")(version 3.0; acl "Users can create and delete tokens"; allow (add, delete) userattr = "ipatokenOwner#SELFDN";)
diff --git a/install/updates/40-otp.update b/install/updates/40-otp.update
index ba9be5f0569edffea6fae6aaee031012414f9353..f84c1661a9e3e93d288fdfb3b064f5f5297973b7 100644
--- a/install/updates/40-otp.update
+++ b/install/updates/40-otp.update
@@ -4,11 +4,17 @@ default: objectClass: top
 default: cn: otp
 
 dn: $SUFFIX
-add: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)'
-add: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)'
-add: aci:'(targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPclockOffset || ipatokenTOTPtimeStep")(version 3.0; acl "Users can add TOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)'
-add: aci:'(target = "ldap:///ipatokenuniqueid=*,cn=otp,$SUFFIX";)(targetfilter = "(objectClass=ipaToken)")(version 3.0; acl "Users can create and delete tokens"; allow (add, delete) userattr = "ipatokenOwner#SELFDN";)'
-add: aci:'(targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenHOTPcounter")(version 3.0; acl "Users can add HOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)'
+remove: aci:'(target = "ldap:///ipatokenuniqueid=*,cn=otp,$SUFFIX";)(targetfilter = "(objectClass=ipaToken)")(version 3.0; acl "Users can create and delete tokens"; allow (add, delete) userattr = "ipatokenOwner#SELFDN";)'
+remove: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)'
+remove: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)'
+remove: aci:'(targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPclockOffset || ipatokenTOTPtimeStep")(version 3.0; acl "Users can add TOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)'
+remove: aci:'(targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenHOTPcounter")(version 3.0; acl "Users can add HOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)'
+add: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || description || ipatokenUniqueID || ipatokenDisabled || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial || ipatokenOwner || ipatokenProtected")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)'
+add: aci:'(targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPtimeStep")(version 3.0; acl "Users can see TOTP details"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)'
+add: aci:'(targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPalgorithm || ipatokenOTPdigits")(version 3.0; acl "Users can see HOTP details"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)'
+add: aci:'(targetfilter = "(&(objectClass=ipaToken)(!(ipatokenProtected=TRUE)))")(targetattrs = "description || ipatokenDisabled || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)'
+add: aci:'(target = "ldap:///ipatokenuniqueid=*,cn=otp,$SUFFIX";)(targetfilter = "(&(objectClass=ipaToken)(!(ipatokenProtected=TRUE))))")(version 3.0; acl "Users can create and delete tokens"; allow (add, delete) userattr = "ipatokenOwner#SELFDN";)'
+
 
 dn: cn=radiusproxy,$SUFFIX
 default: objectClass: nsContainer
diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py
index 42cc16d1686cb411b3170d8ee59ad37986c13772..b401277231eb0398cfb775663a65cb3d642390bd 100644
--- a/ipalib/plugins/otptoken.py
+++ b/ipalib/plugins/otptoken.py
@@ -144,6 +144,10 @@ class otptoken(LDAPObject):
             cli_name='disabled',
             label=_('Disabled state')
         ),
+        Bool('ipatokenprotected?',
+            cli_name='protected',
+            label=_('Protected')
+        ),
         Str('ipatokennotbefore?',
             cli_name='not_before',
             label=_('Validity start'),
@@ -251,6 +255,11 @@ class otptoken_add(LDAPCreate):
         if "ipatokenowner" not in entry_attrs and cur_id is not None:
             entry_attrs["ipatokenowner"] = cur_uid
 
+        # Determine if the token should be protected or not
+        if "ipatokenprotected" not in entry_attrs:
+            if cur_uid != entry_attrs.get('ipatokenowner', None):
+                entry_attrs["ipatokenprotected"] = True
+
         # Resolve the owner's dn
         _normalize_owner(self.api.Object.user, entry_attrs)
 
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index d9c7c6c858aa0a4927efc01fb41b535b7bb04ba2..23b92dcf4b43b3f2c8e56fb69392649889831250 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -672,7 +672,14 @@ class user_del(LDAPDelete):
         results = self.api.Command.otptoken_find(ipatokenowner=owner)['result']
         for token in results:
             token = self.api.Object.otptoken.get_primary_key_from_dn(token['dn'])
-            self.api.Command.otptoken_del(token)
+
+            # If the token is protected, orphan it.
+            if token.get('ipatokenprotected', False):
+                self.api.Command.otptoken_mod(token, ipatokenowner=None)
+
+            # Otherwise, delete it.
+            else:
+                self.api.Command.otptoken_del(token)
 
         return dn
 
-- 
1.9.0

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to