Updated version of this patch so it no longer depends (implicitly) on
the now withdrawn patch 0032.

On Thu, 2014-01-09 at 16:36 -0500, Nathaniel McCallum wrote:
> This patch depends on my patch 0029.
> 
> In the past we have talked about not adding HOTP support due to the
> inability to guarantee timely updates to the counter across replication.
> I went ahead and implemented HOTP support for two reasons:
> 
> 1. Testing the OTP stack with TOTP tokens can be a bit frustrating
> waiting for the tokens to generate.
> 
> 2. Since we aren't implementing watermark support for TOTP, the HOTP
> security guarantee seems very similar to me.
> 
> Nathaniel
> _______________________________________________
> Freeipa-devel mailing list
> [email protected]
> https://www.redhat.com/mailman/listinfo/freeipa-devel

>From aa6745bef88a54d8737d68caa918d0f20a657e9e Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <[email protected]>
Date: Tue, 28 Jan 2014 17:11:04 -0500
Subject: [PATCH] Add HOTP support

---
 API.txt                                           | 10 +++---
 VERSION                                           |  2 +-
 daemons/ipa-slapi-plugins/libotp/libotp.c         | 43 +++++++++++++++++++----
 install/share/70ipaotp.ldif                       |  2 ++
 install/share/default-aci.ldif                    |  3 +-
 install/updates/40-otp.update                     |  1 +
 ipalib/plugins/otptoken.py                        | 26 ++++++++++----
 ipaserver/install/plugins/update_anonymous_aci.py |  2 +-
 8 files changed, 68 insertions(+), 21 deletions(-)

diff --git a/API.txt b/API.txt
index a6c3aed82370d690a678a034b0eea85d4f85b45f..e2f5e036e416bfc248b845c742e3d563958f1772 100644
--- a/API.txt
+++ b/API.txt
@@ -2220,12 +2220,13 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: otptoken_add
-args: 1,20,3
+args: 1,21,3
 arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=False, primary_key=True, required=False)
 option: Str('addattr*', cli_name='addattr', exclude='webui')
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
 option: Bool('ipatokendisabled', attribute=True, cli_name='disabled', multivalue=False, required=False)
+option: Int('ipatokenhotpcounter', attribute=True, cli_name='counter', minvalue=0, multivalue=False, required=False)
 option: Str('ipatokenmodel', attribute=True, cli_name='model', multivalue=False, required=False)
 option: Str('ipatokennotafter', attribute=True, cli_name='not_after', multivalue=False, required=False)
 option: Str('ipatokennotbefore', attribute=True, cli_name='not_before', multivalue=False, required=False)
@@ -2240,7 +2241,7 @@ option: Str('ipatokenvendor', attribute=True, cli_name='vendor', multivalue=Fals
 option: Flag('qrcode?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Str('setattr*', cli_name='setattr', exclude='webui')
-option: StrEnum('type', attribute=False, cli_name='type', multivalue=False, required=False, values=(u'totp',))
+option: StrEnum('type', attribute=False, cli_name='type', multivalue=False, required=False, values=(u'totp', u'hotp'))
 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)
@@ -2254,11 +2255,12 @@ output: Output('result', <type 'dict'>, None)
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: otptoken_find
-args: 1,20,4
+args: 1,21,4
 arg: Str('criteria?', noextrawhitespace=False)
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False)
 option: Bool('ipatokendisabled', attribute=True, autofill=False, cli_name='disabled', multivalue=False, query=True, required=False)
+option: Int('ipatokenhotpcounter', attribute=True, autofill=False, cli_name='counter', minvalue=0, multivalue=False, query=True, required=False)
 option: Str('ipatokenmodel', attribute=True, autofill=False, cli_name='model', multivalue=False, query=True, required=False)
 option: Str('ipatokennotafter', attribute=True, autofill=False, cli_name='not_after', multivalue=False, query=True, required=False)
 option: Str('ipatokennotbefore', attribute=True, autofill=False, cli_name='not_before', multivalue=False, query=True, required=False)
@@ -2274,7 +2276,7 @@ option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Int('sizelimit?', autofill=False, minvalue=0)
 option: Int('timelimit?', autofill=False, minvalue=0)
-option: StrEnum('type', attribute=False, autofill=False, cli_name='type', multivalue=False, query=True, required=False, values=(u'totp',))
+option: StrEnum('type', attribute=False, autofill=False, cli_name='type', multivalue=False, query=True, required=False, values=(u'totp', u'hotp'))
 option: Str('version?', exclude='webui')
 output: Output('count', <type 'int'>, None)
 output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
diff --git a/VERSION b/VERSION
index 5ce16b5224fd95910a221e251b2d740318bded95..3072bfaed6bb02b86dc708fddc7ae0ce3afe3d65 100644
--- a/VERSION
+++ b/VERSION
@@ -89,4 +89,4 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=72
+IPA_API_VERSION_MINOR=73
diff --git a/daemons/ipa-slapi-plugins/libotp/libotp.c b/daemons/ipa-slapi-plugins/libotp/libotp.c
index 3fb298035e86dca7b42b62a328410b94332ea4c6..31cc5915a091f3ebd7cdb430ed4d1304153d5000 100644
--- a/daemons/ipa-slapi-plugins/libotp/libotp.c
+++ b/daemons/ipa-slapi-plugins/libotp/libotp.c
@@ -46,14 +46,17 @@
 #define TOKEN(s) "ipaToken" s
 #define O(s) TOKEN("OTP" s)
 #define T(s) TOKEN("TOTP" s)
+#define H(s) TOKEN("HOTP" s)
 
 #define IPA_OTP_DEFAULT_TOKEN_STEP 30
-#define IPA_OTP_OBJCLS_FILTER "(objectClass=ipaTokenTOTP)"
+#define IPA_OTP_OBJCLS_FILTER \
+    "(|(objectClass=ipaTokenTOTP)(objectClass=ipaTokenHOTP))"
 
 
 enum otptoken_type {
     OTPTOKEN_NONE = 0,
     OTPTOKEN_TOTP,
+    OTPTOKEN_HOTP,
 };
 
 struct otptoken {
@@ -61,10 +64,15 @@ struct otptoken {
     Slapi_DN *sdn;
     struct hotp_token token;
     enum otptoken_type type;
-    struct {
-        unsigned int step;
-        int offset;
-    } totp;
+    union {
+        struct {
+            unsigned int step;
+            int offset;
+        } totp;
+        struct {
+            uint64_t counter;
+        } hotp;
+    };
 };
 
 static const char *get_basedn(Slapi_DN *dn)
@@ -124,6 +132,9 @@ static bool validate(struct otptoken *token, time_t now, ssize_t step,
     case OTPTOKEN_TOTP:
         step = (now + token->totp.offset) / token->totp.step + step;
         break;
+    case OTPTOKEN_HOTP:
+        step = token->hotp.counter + step;
+        break;
     default:
         return false;
     }
@@ -160,6 +171,13 @@ static bool writeback(struct otptoken *token, ssize_t step, bool sync)
         attr = T("clockOffset");
         value = token->totp.offset + step * token->totp.step;
         break;
+    case OTPTOKEN_HOTP:
+        /* Having support for LDAP_MOD_INCREMENT could be helpful here. */
+        if (step < 0)
+            return false; /* NEVER go backwards! */
+        attr = H("counter");
+        value = token->hotp.counter + step;
+        break;
     default:
         return false;
     }
@@ -190,6 +208,9 @@ static bool writeback(struct otptoken *token, ssize_t step, bool sync)
     case OTPTOKEN_TOTP:
         token->totp.offset = value;
         break;
+    case OTPTOKEN_HOTP:
+        token->hotp.counter = value;
+        break;
     default:
         break;
     }
@@ -243,6 +264,8 @@ static struct otptoken *otptoken_new(Slapi_ComponentId *id, Slapi_Entry *entry)
     for (int i = 0; vals[i] != NULL; i++) {
         if (strcasecmp(vals[i], "ipaTokenTOTP") == 0)
             token->type = OTPTOKEN_TOTP;
+        else if (strcasecmp(vals[i], "ipaTokenHOTP") == 0)
+            token->type = OTPTOKEN_HOTP;
     }
     slapi_ch_array_free(vals);
     if (token->type == OTPTOKEN_NONE)
@@ -285,6 +308,10 @@ static struct otptoken *otptoken_new(Slapi_ComponentId *id, Slapi_Entry *entry)
         if (token->totp.step == 0)
             token->totp.step = IPA_OTP_DEFAULT_TOKEN_STEP;
         break;
+    case OTPTOKEN_HOTP:
+        /* Get counter. */
+        token->hotp.counter = slapi_entry_attr_get_int(entry, H("counter"));
+        break;
     default:
         break;
     }
@@ -433,7 +460,8 @@ bool otptoken_validate(struct otptoken *token, size_t steps, uint32_t code)
         if (validate(token, now, i, code, NULL))
             return writeback(token, i + 1, false);
 
-        if (i == 0)
+        /* Counter-based tokens must NEVER validate old steps! */
+        if (i == 0 || token->type == OTPTOKEN_HOTP)
             continue;
 
         /* Validate the negative step. */
@@ -497,7 +525,8 @@ bool otptoken_sync(struct otptoken * const *tokens, size_t steps,
             if (validate(tokens[j], now, i, first_code, &second_code))
                 return writeback(tokens[j], i + 2, true);
 
-            if (i == 0)
+            /* Counter-based tokens must NEVER validate old steps! */
+            if (i == 0 || tokens[j]->type == OTPTOKEN_HOTP)
                 continue;
 
             /* Validate the negative step. */
diff --git a/install/share/70ipaotp.ldif b/install/share/70ipaotp.ldif
index d257a46c38d2e776147e6c2a5c997a33cd100ef1..620c2ccde39ed52dc95fc884b2f1a00f25a5be4c 100644
--- a/install/share/70ipaotp.ldif
+++ b/install/share/70ipaotp.ldif
@@ -22,7 +22,9 @@ attributeTypes: (2.16.840.1.113730.3.8.16.1.17 NAME 'ipatokenRadiusSecret' DESC
 attributeTypes: (2.16.840.1.113730.3.8.16.1.18 NAME 'ipatokenRadiusTimeout' DESC 'Server Timeout' 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.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')
 objectClasses:  (2.16.840.1.113730.3.8.16.2.2  NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MAY (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')
+objectClasses:  (2.16.840.1.113730.3.8.16.2.5  NAME 'ipatokenHOTP' SUP ipaToken STRUCTURAL DESC 'HOTP Token Type' MAY (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenHOTPcounter) X-ORIGIN 'IPA OTP')
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index 9af9ab28c72e35f7912795e5280170cc6e1bdd80..76dd93f4ef2ca5ff6974e6c7ce53f5b7149e55d9 100644
--- a/install/share/default-aci.ldif
+++ b/install/share/default-aci.ldif
@@ -3,7 +3,7 @@
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetfilter = "(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenRadiusConfiguration)))")(target != "ldap:///idnsname=*,cn=dns,$SUFFIX";)(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || userPKCS12 || ipaNTHash || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";;)
+aci: (targetfilter = "(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenHOTP))(!(objectClass=ipatokenRadiusConfiguration)))")(target != "ldap:///idnsname=*,cn=dns,$SUFFIX";)(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || userPKCS12 || ipaNTHash || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";;)
 aci: (targetattr = "memberOf || memberHost || memberUser")(version 3.0; acl "No anonymous access to member information"; deny (read,search,compare) userdn != "ldap:///all";;)
 aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || serverHostName || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";;)
 aci: (targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword")(version 3.0; acl "selfservice:Self can write own password"; allow (write) userdn="ldap:///self";;)
@@ -103,3 +103,4 @@ 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: (targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenHOTPcounter")(version 3.0; acl "Users can add HOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)
diff --git a/install/updates/40-otp.update b/install/updates/40-otp.update
index 83dfab7c03bfeb121756410d79143c3812146de6..750d0f8b3134fb4a81f4d35a1743b8c48113a88f 100644
--- a/install/updates/40-otp.update
+++ b/install/updates/40-otp.update
@@ -7,6 +7,7 @@ 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:'(targetfilter = "(objectClass=ipatokenHOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenHOTPcounter")(version 3.0; acl "Users can add HOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)'
 
 dn: cn=radiusproxy,$SUFFIX
 default: objectClass: nsContainer
diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py
index 67f24859583bb9c72da1faf2f5fdaa1faf69f437..c7c0fe71f2f93d3790be8425764fbe98716ae4ce 100644
--- a/ipalib/plugins/otptoken.py
+++ b/ipalib/plugins/otptoken.py
@@ -53,7 +53,7 @@ EXAMPLES:
 
 register = Registry()
 
-TOKEN_TYPES = (u'totp',)
+TOKEN_TYPES = (u'totp', u'hotp')
 
 # NOTE: For maximum compatibility, KEY_LENGTH % 5 == 0
 KEY_LENGTH = 10
@@ -102,7 +102,7 @@ class otptoken(LDAPObject):
     object_name = _('OTP tokens')
     object_name_plural = _('OTP tokens')
     object_class = ['ipatoken']
-    possible_objectclasses = ['ipatokentotp']
+    possible_objectclasses = ['ipatokentotp', 'ipatokenhotp']
     default_attributes = [
         'ipatokenuniqueid', 'description', 'ipatokenowner',
         'ipatokendisabled', 'ipatokennotbefore', 'ipatokennotafter',
@@ -185,6 +185,12 @@ class otptoken(LDAPObject):
             minvalue=5,
             flags=('no_update'),
         ),
+        Int('ipatokenhotpcounter?',
+            cli_name='counter',
+            label=_('Counter'),
+            minvalue=0,
+            flags=('no_update'),
+        ),
     )
 
 
@@ -213,14 +219,17 @@ class otptoken_add(LDAPCreate):
         entry_attrs.setdefault('ipatokenserial', entry_attrs['ipatokenuniqueid'])
         entry_attrs.setdefault('ipatokenotpalgorithm', u'sha1')
         entry_attrs.setdefault('ipatokenotpdigits', 6)
-        entry_attrs.setdefault('ipatokentotpclockoffset', 0)
-        entry_attrs.setdefault('ipatokentotptimestep', 30)
         entry_attrs.setdefault('ipatokenotpkey',
             "".join(map(chr, random.SystemRandom().sample(range(255), KEY_LENGTH))))
 
-        # Set the object class
+        # Set the object class and defaults for specific token types
         if options['type'] == 'totp':
             entry_attrs['objectclass'] = otptoken.object_class + ['ipatokentotp']
+            entry_attrs.setdefault('ipatokentotpclockoffset', 0)
+            entry_attrs.setdefault('ipatokentotptimestep', 30)
+        elif options['type'] == 'hotp':
+            entry_attrs['objectclass'] = otptoken.object_class + ['ipatokenhotp']
+            entry_attrs.setdefault('ipatokenhotpcounter', 0)
 
         # Resolve the user's dn
         _normalize_owner(self.api.Object.user, entry_attrs)
@@ -239,13 +248,16 @@ class otptoken_add(LDAPCreate):
         args['issuer'] = issuer
         args['secret'] = base64.b32encode(entry_attrs['ipatokenotpkey'])
         args['digits'] = entry_attrs['ipatokenotpdigits']
-        args['period'] = entry_attrs['ipatokentotptimestep']
         args['algorithm'] = entry_attrs['ipatokenotpalgorithm']
+        if options['type'] == 'totp':
+            args['period'] = entry_attrs['ipatokentotptimestep']
+        elif options['type'] == 'hotp':
+            args['counter'] = entry_attrs['ipatokenhotpcounter']
 
         # Build the URI
         label = urllib.quote(entry_attrs['ipatokenuniqueid'])
         parameters = urllib.urlencode(args)
-        uri = u'otpauth://totp/%s:%s?%s' % (issuer, label, parameters)
+        uri = u'otpauth://%s/%s:%s?%s' % (options['type'], issuer, label, parameters)
         setattr(context, 'uri', uri)
 
         return dn
diff --git a/ipaserver/install/plugins/update_anonymous_aci.py b/ipaserver/install/plugins/update_anonymous_aci.py
index 0425754d5a68d73c093f6e20f9a675b0534b2852..943b2457774c964fa66d97496bb66ef1f4e80f1c 100644
--- a/ipaserver/install/plugins/update_anonymous_aci.py
+++ b/ipaserver/install/plugins/update_anonymous_aci.py
@@ -35,7 +35,7 @@ class update_anonymous_aci(PostUpdate):
         aciname = u'Enable Anonymous access'
         aciprefix = u'none'
         ldap = self.obj.backend
-        targetfilter = '(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenRadiusConfiguration)))'
+        targetfilter = '(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenHOTP))(!(objectClass=ipatokenRadiusConfiguration)))'
         filter = None
 
         entry_attrs = ldap.get_entry(api.env.basedn, ['aci'])
-- 
1.8.5.3

_______________________________________________
Freeipa-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to