Commit 87f3bad8 authored by Ondřej Kuzník's avatar Ondřej Kuzník Committed by Quanah Gibson-Mount
Browse files

ITS#9437 Add otp_2fa overlay

parent 3bd1b090
......@@ -351,6 +351,7 @@ Overlays="accesslog \
dynlist \
homedir \
memberof \
otp \
ppolicy \
proxycache \
refint \
......@@ -393,6 +394,8 @@ OL_ARG_ENABLE(homedir, [AS_HELP_STRING([--enable-homedir], [Home Directory Manag
no, [no yes mod], ol_enable_overlays)
OL_ARG_ENABLE(memberof, [AS_HELP_STRING([--enable-memberof], [Reverse Group Membership overlay])],
no, [no yes mod], ol_enable_overlays)
OL_ARG_ENABLE(otp, [AS_HELP_STRING([--enable-otp], [OTP 2-factor authentication overlay])],
no, [no yes mod], ol_enable_overlays)
OL_ARG_ENABLE(ppolicy, [AS_HELP_STRING([--enable-ppolicy], [Password Policy overlay])],
no, [no yes mod], ol_enable_overlays)
OL_ARG_ENABLE(proxycache, [AS_HELP_STRING([--enable-proxycache], [Proxy Cache overlay])],
......@@ -593,6 +596,7 @@ BUILD_DYNLIST=no
BUILD_LASTMOD=no
BUILD_HOMEDIR=no
BUILD_MEMBEROF=no
BUILD_OTP=no
BUILD_PPOLICY=no
BUILD_PROXYCACHE=no
BUILD_REFINT=no
......@@ -2867,6 +2871,22 @@ if test "$ol_enable_memberof" != no ; then
AC_DEFINE_UNQUOTED(SLAPD_OVER_MEMBEROF,$MFLAG,[define for Reverse Group Membership overlay])
fi
if test "$ol_enable_otp" != no ; then
if test $ol_with_tls = no ; then
AC_MSG_ERROR([--enable-otp=$ol_enable_otp requires --with-tls])
fi
BUILD_OTP=$ol_enable_otp
if test "$ol_enable_otp" = mod ; then
MFLAG=SLAPD_MOD_DYNAMIC
SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS otp_2fa.la"
else
MFLAG=SLAPD_MOD_STATIC
SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS otp_2fa.o"
fi
AC_DEFINE_UNQUOTED(SLAPD_OVER_OTP,$MFLAG,[define for OTP 2-factor Authentication overlay])
fi
if test "$ol_enable_ppolicy" != no ; then
BUILD_PPOLICY=$ol_enable_ppolicy
if test "$ol_enable_ppolicy" = mod ; then
......@@ -3142,6 +3162,7 @@ dnl overlays
AC_SUBST(BUILD_LASTMOD)
AC_SUBST(BUILD_HOMEDIR)
AC_SUBST(BUILD_MEMBEROF)
AC_SUBST(BUILD_OTP)
AC_SUBST(BUILD_PPOLICY)
AC_SUBST(BUILD_PROXYCACHE)
AC_SUBST(BUILD_REFINT)
......
.TH PW-TOTP 5 "2018/6/29" "SLAPO-OTP_2FA"
.\" Copyright 2015-2021 The OpenLDAP Foundation.
.\" Portions Copyright 2015 by Howard Chu, Symas Corp. All rights reserved.
.\" Portions Copyright 2018 by Ondřej Kuzník, Symas Corp. All rights reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
slapo-otp \- Two factor authentication module
.SH SYNOPSIS
.B moduleload
.I otp_2fa.la
.SH DESCRIPTION
The
.B otp_2fa
module allows time-based one-time password, AKA "authenticator-style", and
HMAC-based one-time password authentication to be used in applications that use
LDAP for authentication. In most cases no changes to the applications are
needed to switch to this type of authentication.
With this module, users would use their password, followed with the one-time
password in the password prompt to authenticate.
The password needed for a user to authenticate is calculated based on a counter
(current time in case of TOTP) and a key that is referenced in the user's LDAP
entry. Since the password is based on the time or number of uses, it changes
periodically. Once used, it cannot be used again so keyloggers and
shoulder-surfers are thwarted. A mobile phone application, such as the Google
Authenticator or YubiKey (a
.BR prover ),
can be used to calculate the user's current one-time password, which is
expressed as a (usually six-digit) number.
Alternatively, the value can be calculated by some other application with
access to the user's key and delivered to the user through SMS or some other
channel. When prompted to authenticate, the user merely appends the code
provided by the prover at the end of their password when authenticating.
This implementation complies with
.B RFC 4226 HOTP HMAC-Based One Time Passwords
and
.B RFC 6238 TOTP Time-based One Time Passwords
and includes support for the SHA-1, SHA-256, and SHA-512 HMAC
algorithms.
The HMAC key used in the OTP computation is stored in the oathOTPToken entry referenced in
the user's LDAP entry and the parameters are stored in the oathOTPParams LDAP
entry referenced in the token.
.SH CONFIGURATION
Once the module is configured on the database, it will intercept LDAP simple
binds for users whose LDAP entry has any of the
.B oathOTPUser
derived objectlasses attached to it. The attributes linking the user and the
shared secret are:
.RS
.TP
.B oathTOTPToken: <dn>
Mandatory for
.BR oathTOTPUser ,
indicates that the named entry is designated to hold the time-based one-time
password shared secret and the last password used.
.TP
.B oathHOTPToken: <dn>
Mandatory for
.BR oathHOTPUser ,
indicates that the named entry is designated to hold the one-time password
shared secret and the last password used.
.TP
.B oathTOTPParams: <dn>
Mandatory for
.BR oathTOTPToken ,
indicates that the named entry is designated to hold the parameters to generate
time-based one-time password shared secret: its length and algorithm to use as
well as the length of each time step and the grace period.
.TP
.B oathHOTPParams: <dn>
Mandatory for
.BR oathHOTPToken ,
indicates that the named entry is designated to hold the parameters to generate
one-time password shared secret: its length and algorithm to use as well as the
permitted number of passwords to skip.
.RE
The following parts of the OATH-LDAP schema are implemented.
General attributes:
.RS
.TP
.B oathSecret: <data>
The shared secret is stored here as raw bytes.
.TP
.B oathOTPLength: <length>
The password length, usually 6.
.TP
.B oathHMACAlgorithm: <OID>
The OID of the hash algorithm to use as defined in RFC 8018.
Supported algorithms include SHA1, SHA224, SHA256, SHA384 and SHA512.
.RE
The HOTP attributes:
.RS
.TP
.B oathHOTPLookAhead: <number>
The number of successive HOTP tokens that can be skipped.
.TP
.B oathHOTPCounter: <number>
The order of the last HOTP token successfully redeemed by the user.
.RE
The TOTP attributes:
.RS
.TP
.B oathTOTPTimeStepPeriod: <seconds>
The length of the time-step period for TOTP calculation.
.TP
.B oathTOTPLastTimeStep: <number>
The order of the last TOTP token successfully redeemed by the user.
.TP
.B oathTOTPGrace: <number>
The number of time periods around the current time to try when checking the
password provided by the user.
.RE
.SH "SEE ALSO"
.BR slapd\-config (5).
.SH ACKNOWLEDGEMENT
This work was developed by Ondřej Kuzník and Howard Chu of Symas Corporation
for inclusion in OpenLDAP Software.
This work reuses the OATH-LDAP schema developed by Michael Ströder.
......@@ -24,6 +24,7 @@ SRCS = overlays.c \
dynlist.c \
homedir.c \
memberof.c \
otp_2fa.c \
pcache.c \
collect.c \
ppolicy.c \
......@@ -95,6 +96,9 @@ homedir.la : homedir.lo
memberof.la : memberof.lo
$(LTLINK_MOD) -module -o $@ memberof.lo version.lo $(LINK_LIBS)
otp_2fa.la : otp_2fa.lo
$(LTLINK_MOD) -module -o $@ otp_2fa.lo version.lo $(LINK_LIBS)
pcache.la : pcache.lo
$(LTLINK_MOD) -module -o $@ pcache.lo version.lo $(LINK_LIBS)
......
/* otp_2fa.c - OATH 2-factor authentication module */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2015-2021 The OpenLDAP Foundation.
* Portions Copyright 2015 by Howard Chu, Symas Corp.
* Portions Copyright 2016-2017 by Michael Ströder <michael@stroeder.com>
* Portions Copyright 2018 by Ondřej Kuzník, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work includes code from the lastbind overlay.
*/
#include <portable.h>
#ifdef SLAPD_OVER_OTP
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <lber.h>
#include <lber_pvt.h>
#include "lutil.h"
#include <ac/stdlib.h>
#include <ac/ctype.h>
#include <ac/string.h>
/* include socket.h to get sys/types.h and/or winsock2.h */
#include <ac/socket.h>
#if HAVE_OPENSSL
#include <openssl/sha.h>
#include <openssl/hmac.h>
#define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_LENGTH
#define TOTP_SHA1 EVP_sha1()
#define TOTP_SHA224 EVP_sha224()
#define TOTP_SHA256 EVP_sha256()
#define TOTP_SHA384 EVP_sha384()
#define TOTP_SHA512 EVP_sha512()
#define TOTP_HMAC_CTX HMAC_CTX *
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static HMAC_CTX *
HMAC_CTX_new( void )
{
HMAC_CTX *ctx = OPENSSL_malloc( sizeof(*ctx) );
if ( ctx != NULL ) {
HMAC_CTX_init( ctx );
}
return ctx;
}
static void
HMAC_CTX_free( HMAC_CTX *ctx )
{
if ( ctx != NULL ) {
HMAC_CTX_cleanup( ctx );
OPENSSL_free( ctx );
}
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
#define HMAC_setup( ctx, key, len, hash ) \
ctx = HMAC_CTX_new(); \
HMAC_Init_ex( ctx, key, len, hash, 0 )
#define HMAC_crunch( ctx, buf, len ) HMAC_Update( ctx, buf, len )
#define HMAC_finish( ctx, dig, dlen ) \
HMAC_Final( ctx, dig, &dlen ); \
HMAC_CTX_free( ctx )
#elif HAVE_GNUTLS
#include <nettle/hmac.h>
#define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_SIZE
#define TOTP_SHA1 &nettle_sha1
#define TOTP_SHA224 &nettle_sha224
#define TOTP_SHA256 &nettle_sha256
#define TOTP_SHA384 &nettle_sha384
#define TOTP_SHA512 &nettle_sha512
#define TOTP_HMAC_CTX struct hmac_sha512_ctx
#define HMAC_setup( ctx, key, len, hash ) \
const struct nettle_hash *h = hash; \
hmac_set_key( &ctx.outer, &ctx.inner, &ctx.state, h, len, key )
#define HMAC_crunch( ctx, buf, len ) hmac_update( &ctx.state, h, len, buf )
#define HMAC_finish( ctx, dig, dlen ) \
hmac_digest( &ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig ); \
dlen = h->digest_size
#else
#error Unsupported crypto backend.
#endif
#include "slap.h"
#include "slap-config.h"
/* Schema from OATH-LDAP project by Michael Ströder */
static struct {
char *name, *oid;
} otp_oid[] = {
{ "oath-ldap", "1.3.6.1.4.1.5427.1.389.4226" },
{ "oath-ldap-at", "oath-ldap:4" },
{ "oath-ldap-oc", "oath-ldap:6" },
{ NULL }
};
AttributeDescription *ad_oathOTPToken;
AttributeDescription *ad_oathSecret;
AttributeDescription *ad_oathOTPLength;
AttributeDescription *ad_oathHMACAlgorithm;
AttributeDescription *ad_oathHOTPParams;
AttributeDescription *ad_oathHOTPToken;
AttributeDescription *ad_oathHOTPCounter;
AttributeDescription *ad_oathHOTPLookahead;
AttributeDescription *ad_oathTOTPTimeStepPeriod;
AttributeDescription *ad_oathTOTPParams;
AttributeDescription *ad_oathTOTPToken;
AttributeDescription *ad_oathTOTPLastTimeStep;
AttributeDescription *ad_oathTOTPTimeStepWindow;
static struct otp_at {
char *schema;
AttributeDescription **adp;
} otp_at[] = {
{ "( oath-ldap-at:1 "
"NAME 'oathSecret' "
"DESC 'OATH-LDAP: Shared Secret (possibly encrypted with public key in oathEncKey)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY octetStringMatch "
"SUBSTR octetStringSubstringsMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
&ad_oathSecret },
{ "( oath-ldap-at:2 "
"NAME 'oathTokenSerialNumber' "
"DESC 'OATH-LDAP: Proprietary hardware token serial number assigned by vendor' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY caseIgnoreMatch "
"SUBSTR caseIgnoreSubstringsMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64})" },
{ "( oath-ldap-at:3 "
"NAME 'oathTokenIdentifier' "
"DESC 'OATH-LDAP: Globally unique OATH token identifier' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY caseIgnoreMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )" },
{ "( oath-ldap-at:4 "
"NAME 'oathParamsEntry' "
"DESC 'OATH-LDAP: DN pointing to OATH parameter/policy object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP distinguishedName )" },
{ "( oath-ldap-at:4.1 "
"NAME 'oathTOTPTimeStepPeriod' "
"DESC 'OATH-LDAP: Time window for TOTP (seconds)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
&ad_oathTOTPTimeStepPeriod },
{ "( oath-ldap-at:5 "
"NAME 'oathOTPLength' "
"DESC 'OATH-LDAP: Length of OTP (number of digits)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
&ad_oathOTPLength },
{ "( oath-ldap-at:5.1 "
"NAME 'oathHOTPParams' "
"DESC 'OATH-LDAP: DN pointing to HOTP parameter object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathParamsEntry )",
&ad_oathHOTPParams },
{ "( oath-ldap-at:5.2 "
"NAME 'oathTOTPParams' "
"DESC 'OATH-LDAP: DN pointing to TOTP parameter object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathParamsEntry )",
&ad_oathTOTPParams },
{ "( oath-ldap-at:6 "
"NAME 'oathHMACAlgorithm' "
"DESC 'OATH-LDAP: HMAC algorithm used for generating OTP values' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY objectIdentifierMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
&ad_oathHMACAlgorithm },
{ "( oath-ldap-at:7 "
"NAME 'oathTimestamp' "
"DESC 'OATH-LDAP: Timestamp (not directly used).' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY generalizedTimeMatch "
"ORDERING generalizedTimeOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )" },
{ "( oath-ldap-at:7.1 "
"NAME 'oathLastFailure' "
"DESC 'OATH-LDAP: Timestamp of last failed OATH validation' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathTimestamp )" },
{ "( oath-ldap-at:7.2 "
"NAME 'oathLastLogin' "
"DESC 'OATH-LDAP: Timestamp of last successful OATH validation' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathTimestamp )" },
{ "( oath-ldap-at:7.3 "
"NAME 'oathSecretTime' "
"DESC 'OATH-LDAP: Timestamp of generation of oathSecret attribute.' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathTimestamp )" },
{ "( oath-ldap-at:8 "
"NAME 'oathSecretMaxAge' "
"DESC 'OATH-LDAP: Time in seconds for which the shared secret (oathSecret) will be valid from oathSecretTime value.' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )" },
{ "( oath-ldap-at:9 "
"NAME 'oathToken' "
"DESC 'OATH-LDAP: DN pointing to OATH token object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP distinguishedName )" },
{ "( oath-ldap-at:9.1 "
"NAME 'oathHOTPToken' "
"DESC 'OATH-LDAP: DN pointing to OATH/HOTP token object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathToken )",
&ad_oathHOTPToken },
{ "( oath-ldap-at:9.2 "
"NAME 'oathTOTPToken' "
"DESC 'OATH-LDAP: DN pointing to OATH/TOTP token object' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathToken )",
&ad_oathTOTPToken },
{ "( oath-ldap-at:10 "
"NAME 'oathCounter' "
"DESC 'OATH-LDAP: Counter for OATH data (not directly used)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )" },
{ "( oath-ldap-at:10.1 "
"NAME 'oathFailureCount' "
"DESC 'OATH-LDAP: OATH failure counter' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )" },
{ "( oath-ldap-at:10.2 "
"NAME 'oathHOTPCounter' "
"DESC 'OATH-LDAP: Counter for HOTP' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )",
&ad_oathHOTPCounter },
{ "( oath-ldap-at:10.3 "
"NAME 'oathHOTPLookAhead' "
"DESC 'OATH-LDAP: Look-ahead window for HOTP' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )",
&ad_oathHOTPLookahead },
{ "( oath-ldap-at:10.5 "
"NAME 'oathThrottleLimit' "
"DESC 'OATH-LDAP: Failure throttle limit' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )" },
{ "( oath-ldap-at:10.6 "
"NAME 'oathTOTPLastTimeStep' "
"DESC 'OATH-LDAP: Last time step seen for TOTP (time/period)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )",
&ad_oathTOTPLastTimeStep },
{ "( oath-ldap-at:10.7 "
"NAME 'oathMaxUsageCount' "
"DESC 'OATH-LDAP: Maximum number of times a token can be used' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )" },
{ "( oath-ldap-at:10.8 "
"NAME 'oathTOTPTimeStepWindow' "
"DESC 'OATH-LDAP: Size of time step +/- tolerance window used for TOTP validation' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )",
&ad_oathTOTPTimeStepWindow },
{ "( oath-ldap-at:10.9 "
"NAME 'oathTOTPTimeStepDrift' "
"DESC 'OATH-LDAP: Last observed time step shift seen for TOTP' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"SUP oathCounter )" },
{ "( oath-ldap-at:11 "
"NAME 'oathSecretLength' "
"DESC 'OATH-LDAP: Length of plain-text shared secret (number of bytes)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )" },
{ "( oath-ldap-at:12 "
"NAME 'oathEncKey' "
"DESC 'OATH-LDAP: public key to be used for encrypting new shared secrets' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY caseIgnoreMatch "
"SUBSTR caseIgnoreSubstringsMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" },
{ "( oath-ldap-at:13 "
"NAME 'oathResultCode' "
"DESC 'OATH-LDAP: LDAP resultCode to use in response' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY integerMatch "
"ORDERING integerOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )" },
{ "( oath-ldap-at:13.1 "
"NAME 'oathSuccessResultCode' "
"DESC 'OATH-LDAP: success resultCode to use in bind/compare response' "
"X-ORIGIN 'OATH-LDAP' "
"SUP oathResultCode )" },
{ "( oath-ldap-at:13.2 "
"NAME 'oathFailureResultCode' "
"DESC 'OATH-LDAP: failure resultCode to use in bind/compare response' "
"X-ORIGIN 'OATH-LDAP' "
"SUP oathResultCode )" },
{ "( oath-ldap-at:14 "
"NAME 'oathTokenPIN' "
"DESC 'OATH-LDAP: Configuration PIN (possibly encrypted with oathEncKey)' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY caseIgnoreMatch "
"SUBSTR caseIgnoreSubstringsMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" },
{ "( oath-ldap-at:15 "
"NAME 'oathMessage' "
"DESC 'OATH-LDAP: success diagnosticMessage to use in bind/compare response' "
"X-ORIGIN 'OATH-LDAP' "
"SINGLE-VALUE "
"EQUALITY caseIgnoreMatch "
"SUBSTR caseIgnoreSubstringsMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )" },
{ "( oath-ldap-at:15.1 "
"NAME 'oathSuccessMessage' "
"DESC 'OATH-LDAP: success diagnosticMessage to use in bind/compare response' "
"X-ORIGIN 'OATH-LDAP' "
"SUP oathMessage )" },
{ "( oath-ldap-at:15.2 "
"NAME 'oathFailureMessage' "
"DESC 'OATH-LDAP: failure diagnosticMessage to use in bind/compare response' "
"X-ORIGIN 'OATH-LDAP' "
"SUP oathMessage )" },
{ NULL }
};
ObjectClass *oc_oathOTPUser;
ObjectClass *oc_oathHOTPToken;
ObjectClass *oc_oathTOTPToken;
ObjectClass *oc_oathHOTPParams;
ObjectClass *oc_oathTOTPParams;
static struct otp_oc {
char *schema;
ObjectClass **ocp;
} otp_oc[] = {
{ "( oath-ldap-oc:1 "
"NAME 'oathUser' "
"DESC 'OATH-LDAP: User Object' "
"X-ORIGIN 'OATH-LDAP' "
"ABSTRACT )",
&oc_oathOTPUser },
{ "( oath-ldap-oc:1.1 "
"NAME 'oathHOTPUser' "
"DESC 'OATH-LDAP: HOTP user object' "
"X-ORIGIN 'OATH-LDAP' "
"AUXILIARY "
"SUP oathUser "
"MAY ( oathHOTPToken ) )" },
{ "( oath-ldap-oc:1.2 "
"NAME 'oathTOTPUser' "
"DESC 'OATH-LDAP: TOTP user object' "
"X-ORIGIN 'OATH-LDAP' "
"AUXILIARY "
"SUP oathUser "
"MUST ( oathTOTPToken ) )" },
{ "( oath-ldap-oc:2 "
"NAME 'oathParams' "
"DESC 'OATH-LDAP: Parameter object' "
"X-OR