Blame SOURCES/0009-Issue-4972-gecos-with-IA5-introduces-a-compatibility.patch

51b5b9
From 2ae2f53756b6f13e2816bb30812740cb7ad97403 Mon Sep 17 00:00:00 2001
51b5b9
From: tbordaz <tbordaz@redhat.com>
51b5b9
Date: Fri, 5 Nov 2021 09:56:43 +0100
51b5b9
Subject: [PATCH 09/12] Issue 4972 - gecos with IA5 introduces a compatibility
51b5b9
 issue with previous (#4981)
51b5b9
51b5b9
releases where it was DirectoryString
51b5b9
51b5b9
Bug description:
51b5b9
       For years 'gecos' was DirectoryString (UTF8), with #50933 it was restricted to IA5 (ascii)
51b5b9
       https://github.com/389ds/389-ds-base/commit/0683bcde1b667b6d0ca6e8d1ef605f17c51ea2f7#
51b5b9
51b5b9
       IA5 definition conforms rfc2307 but is a problem for existing deployments
51b5b9
       where entries can have 'gecos' attribute value with UTF8.
51b5b9
51b5b9
Fix description:
51b5b9
       Revert the definition to of 'gecos' being Directory String
51b5b9
51b5b9
       Additional fix to make test_replica_backup_and_restore more
51b5b9
       robust to CI
51b5b9
51b5b9
relates: https://github.com/389ds/389-ds-base/issues/4972
51b5b9
51b5b9
Reviewed by: William Brown, Pierre Rogier, James Chapman (Thanks !)
51b5b9
51b5b9
Platforms tested: F34
51b5b9
---
51b5b9
 .../tests/suites/schema/schema_test.py        | 398 +++++++++++++++++-
51b5b9
 ldap/schema/10rfc2307compat.ldif              |   6 +-
51b5b9
 2 files changed, 400 insertions(+), 4 deletions(-)
51b5b9
51b5b9
diff --git a/dirsrvtests/tests/suites/schema/schema_test.py b/dirsrvtests/tests/suites/schema/schema_test.py
51b5b9
index d590624b6..5d62b8d59 100644
51b5b9
--- a/dirsrvtests/tests/suites/schema/schema_test.py
51b5b9
+++ b/dirsrvtests/tests/suites/schema/schema_test.py
51b5b9
@@ -18,8 +18,12 @@ import pytest
51b5b9
 import six
51b5b9
 from ldap.cidict import cidict
51b5b9
 from ldap.schema import SubSchema
51b5b9
+from lib389.schema import SchemaLegacy
51b5b9
 from lib389._constants import *
51b5b9
-from lib389.topologies import topology_st
51b5b9
+from lib389.topologies import topology_st, topology_m2 as topo_m2
51b5b9
+from lib389.idm.user import UserAccounts, UserAccount
51b5b9
+from lib389.replica import ReplicationManager
51b5b9
+from lib389.utils import ensure_bytes
51b5b9
 
51b5b9
 pytestmark = pytest.mark.tier1
51b5b9
 
51b5b9
@@ -165,6 +169,398 @@ def test_schema_comparewithfiles(topology_st):
51b5b9
 
51b5b9
     log.info('test_schema_comparewithfiles: PASSED')
51b5b9
 
51b5b9
+def test_gecos_directoryString(topology_st):
51b5b9
+    """Check that gecos supports directoryString value
51b5b9
+
51b5b9
+    :id: aee422bb-6299-4124-b5cd-d7393dac19d3
51b5b9
+
51b5b9
+    :setup: Standalone instance
51b5b9
+
51b5b9
+    :steps:
51b5b9
+        1. Add a common user
51b5b9
+        2. replace gecos with a direstoryString value
51b5b9
+
51b5b9
+    :expectedresults:
51b5b9
+        1. Success
51b5b9
+        2. Success
51b5b9
+    """
51b5b9
+
51b5b9
+    users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
51b5b9
+
51b5b9
+    user_properties = {
51b5b9
+        'uid': 'testuser',
51b5b9
+        'cn' : 'testuser',
51b5b9
+        'sn' : 'user',
51b5b9
+        'uidNumber' : '1000',
51b5b9
+        'gidNumber' : '2000',
51b5b9
+        'homeDirectory' : '/home/testuser',
51b5b9
+    }
51b5b9
+    testuser = users.create(properties=user_properties)
51b5b9
+
51b5b9
+    # Add a gecos UTF value
51b5b9
+    testuser.replace('gecos', 'Hélène')
51b5b9
+
51b5b9
+def test_gecos_mixed_definition_topo(topo_m2, request):
51b5b9
+    """Check that replication is still working if schema contains
51b5b9
+       definitions that does not conform with a replicated entry
51b5b9
+
51b5b9
+    :id: d5940e71-d18a-4b71-aaf7-b9185361fffe
51b5b9
+    :setup: Two suppliers replication setup
51b5b9
+    :steps:
51b5b9
+        1. Create a testuser on M1
51b5b9
+        2  Stop M1 and M2
51b5b9
+        3  Change gecos def on M2 to be IA5
51b5b9
+        4  Update testuser with gecos directoryString value
51b5b9
+        5  Check replication is still working
51b5b9
+    :expectedresults:
51b5b9
+        1. success
51b5b9
+        2. success
51b5b9
+        3. success
51b5b9
+        4. success
51b5b9
+        5. success
51b5b9
+
51b5b9
+    """
51b5b9
+
51b5b9
+    repl = ReplicationManager(DEFAULT_SUFFIX)
51b5b9
+    m1 = topo_m2.ms["supplier1"]
51b5b9
+    m2 = topo_m2.ms["supplier2"]
51b5b9
+    
51b5b9
+
51b5b9
+    # create a test user
51b5b9
+    testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
51b5b9
+    testuser = UserAccount(m1, testuser_dn)
51b5b9
+    try:
51b5b9
+        testuser.create(properties={
51b5b9
+            'uid': 'testuser',
51b5b9
+            'cn': 'testuser',
51b5b9
+            'sn': 'testuser',
51b5b9
+            'uidNumber' : '1000',
51b5b9
+            'gidNumber' : '2000',
51b5b9
+            'homeDirectory' : '/home/testuser',
51b5b9
+        })
51b5b9
+    except ldap.ALREADY_EXISTS:
51b5b9
+        pass
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+    # Stop suppliers to update the schema
51b5b9
+    m1.stop()
51b5b9
+    m2.stop()
51b5b9
+
51b5b9
+    # on M1: gecos is DirectoryString (default)
51b5b9
+    # on M2: gecos is IA5
51b5b9
+    schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+    try:
51b5b9
+        with open(schema_filename, 'w') as schema_file:
51b5b9
+            schema_file.write("dn: cn=schema\n")
51b5b9
+            schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
51b5b9
+                              "'gecos' DESC 'The GECOS field; the common name' " +
51b5b9
+                              "EQUALITY caseIgnoreIA5Match " +
51b5b9
+                              "SUBSTR caseIgnoreIA5SubstringsMatch " +
51b5b9
+                              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
51b5b9
+                              "SINGLE-VALUE )\n")
51b5b9
+        os.chmod(schema_filename, 0o777)
51b5b9
+    except OSError as e:
51b5b9
+        log.fatal("Failed to update schema file: " +
51b5b9
+                  "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+
51b5b9
+    # start the instances
51b5b9
+    m1.start()
51b5b9
+    m2.start()
51b5b9
+
51b5b9
+    # Check that gecos is IA5 on M2
51b5b9
+    schema = SchemaLegacy(m2)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
51b5b9
+
51b5b9
+
51b5b9
+    # Add a gecos UTF value on M1
51b5b9
+    testuser.replace('gecos', 'Hélène')
51b5b9
+
51b5b9
+    # Check replication is still working
51b5b9
+    testuser.replace('displayName', 'ascii value')
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+    testuser_m2 = UserAccount(m2, testuser_dn)
51b5b9
+    assert testuser_m2.exists()
51b5b9
+    assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        m1.start()
51b5b9
+        m2.start()
51b5b9
+        testuser.delete()
51b5b9
+        repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+        # on M2 restore a default 99user.ldif
51b5b9
+        m2.stop()
51b5b9
+        os.remove(m2.schemadir + "/99user.ldif")
51b5b9
+        schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+        try:
51b5b9
+            with open(schema_filename, 'w') as schema_file:
51b5b9
+                schema_file.write("dn: cn=schema\n")
51b5b9
+            os.chmod(schema_filename, 0o777)
51b5b9
+        except OSError as e:
51b5b9
+            log.fatal("Failed to update schema file: " +
51b5b9
+                      "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+        m2.start()
51b5b9
+        m1.start()
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
+def test_gecos_directoryString_wins_M1(topo_m2, request):
51b5b9
+    """Check that if inital syntax are IA5(M2) and DirectoryString(M1)
51b5b9
+    Then directoryString wins when nsSchemaCSN M1 is the greatest
51b5b9
+
51b5b9
+    :id: ad119fa5-7671-45c8-b2ef-0b28ffb68fdb
51b5b9
+    :setup: Two suppliers replication setup
51b5b9
+    :steps:
51b5b9
+        1. Create a testuser on M1
51b5b9
+        2  Stop M1 and M2
51b5b9
+        3  Change gecos def on M2 to be IA5
51b5b9
+        4  Start M1 and M2
51b5b9
+        5  Update M1 schema so that M1 has greatest nsSchemaCSN
51b5b9
+        6  Update testuser with gecos directoryString value
51b5b9
+        7  Check replication is still working
51b5b9
+        8  Check gecos is DirectoryString on M1 and M2
51b5b9
+    :expectedresults:
51b5b9
+        1. success
51b5b9
+        2. success
51b5b9
+        3. success
51b5b9
+        4. success
51b5b9
+        5. success
51b5b9
+        6. success
51b5b9
+        7. success
51b5b9
+        8. success
51b5b9
+
51b5b9
+    """
51b5b9
+
51b5b9
+    repl = ReplicationManager(DEFAULT_SUFFIX)
51b5b9
+    m1 = topo_m2.ms["supplier1"]
51b5b9
+    m2 = topo_m2.ms["supplier2"]
51b5b9
+    
51b5b9
+
51b5b9
+    # create a test user
51b5b9
+    testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
51b5b9
+    testuser = UserAccount(m1, testuser_dn)
51b5b9
+    try:
51b5b9
+        testuser.create(properties={
51b5b9
+            'uid': 'testuser',
51b5b9
+            'cn': 'testuser',
51b5b9
+            'sn': 'testuser',
51b5b9
+            'uidNumber' : '1000',
51b5b9
+            'gidNumber' : '2000',
51b5b9
+            'homeDirectory' : '/home/testuser',
51b5b9
+        })
51b5b9
+    except ldap.ALREADY_EXISTS:
51b5b9
+        pass
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+    # Stop suppliers to update the schema
51b5b9
+    m1.stop()
51b5b9
+    m2.stop()
51b5b9
+
51b5b9
+    # on M1: gecos is DirectoryString (default)
51b5b9
+    # on M2: gecos is IA5
51b5b9
+    schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+    try:
51b5b9
+        with open(schema_filename, 'w') as schema_file:
51b5b9
+            schema_file.write("dn: cn=schema\n")
51b5b9
+            schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
51b5b9
+                              "'gecos' DESC 'The GECOS field; the common name' " +
51b5b9
+                              "EQUALITY caseIgnoreIA5Match " +
51b5b9
+                              "SUBSTR caseIgnoreIA5SubstringsMatch " +
51b5b9
+                              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
51b5b9
+                              "SINGLE-VALUE )\n")
51b5b9
+        os.chmod(schema_filename, 0o777)
51b5b9
+    except OSError as e:
51b5b9
+        log.fatal("Failed to update schema file: " +
51b5b9
+                  "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+
51b5b9
+    # start the instances
51b5b9
+    m1.start()
51b5b9
+    m2.start()
51b5b9
+
51b5b9
+    # Check that gecos is IA5 on M2
51b5b9
+    schema = SchemaLegacy(m2)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
51b5b9
+
51b5b9
+
51b5b9
+    # update M1 schema to increase its nsschemaCSN
51b5b9
+    new_at = "( dummy-oid NAME 'dummy' DESC 'dummy attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )"
51b5b9
+    m1.schema.add_schema('attributetypes', ensure_bytes(new_at))
51b5b9
+
51b5b9
+    # Add a gecos UTF value on M1
51b5b9
+    testuser.replace('gecos', 'Hélène')
51b5b9
+
51b5b9
+    # Check replication is still working
51b5b9
+    testuser.replace('displayName', 'ascii value')
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+    testuser_m2 = UserAccount(m2, testuser_dn)
51b5b9
+    assert testuser_m2.exists()
51b5b9
+    assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
51b5b9
+
51b5b9
+    # Check that gecos is DirectoryString on M1
51b5b9
+    schema = SchemaLegacy(m1)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
51b5b9
+
51b5b9
+    # Check that gecos is DirectoryString on M2
51b5b9
+    schema = SchemaLegacy(m2)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        m1.start()
51b5b9
+        m2.start()
51b5b9
+        testuser.delete()
51b5b9
+        m1.schema.del_schema('attributetypes', ensure_bytes(new_at))
51b5b9
+        repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+        # on M2 restore a default 99user.ldif
51b5b9
+        m2.stop()
51b5b9
+        os.remove(m2.schemadir + "/99user.ldif")
51b5b9
+        schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+        try:
51b5b9
+            with open(schema_filename, 'w') as schema_file:
51b5b9
+                schema_file.write("dn: cn=schema\n")
51b5b9
+            os.chmod(schema_filename, 0o777)
51b5b9
+        except OSError as e:
51b5b9
+            log.fatal("Failed to update schema file: " +
51b5b9
+                      "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+        m2.start()
51b5b9
+        m1.start()
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
+def test_gecos_directoryString_wins_M2(topo_m2, request):
51b5b9
+    """Check that if inital syntax are IA5(M2) and DirectoryString(M1)
51b5b9
+    Then directoryString wins when nsSchemaCSN M2 is the greatest
51b5b9
+
51b5b9
+    :id: 2da7f1b1-f86d-4072-a940-ba56d4bc8348
51b5b9
+    :setup: Two suppliers replication setup
51b5b9
+    :steps:
51b5b9
+        1. Create a testuser on M1
51b5b9
+        2  Stop M1 and M2
51b5b9
+        3  Change gecos def on M2 to be IA5
51b5b9
+        4  Start M1 and M2
51b5b9
+        5  Update M2 schema so that M2 has greatest nsSchemaCSN
51b5b9
+        6  Update testuser on M2 and trigger replication to M1
51b5b9
+        7  Update testuser on M2 with gecos directoryString value
51b5b9
+        8  Check replication is still working
51b5b9
+        9  Check gecos is DirectoryString on M1 and M2
51b5b9
+    :expectedresults:
51b5b9
+        1. success
51b5b9
+        2. success
51b5b9
+        3. success
51b5b9
+        4. success
51b5b9
+        5. success
51b5b9
+        6. success
51b5b9
+        7. success
51b5b9
+        8. success
51b5b9
+        9. success
51b5b9
+
51b5b9
+    """
51b5b9
+
51b5b9
+    repl = ReplicationManager(DEFAULT_SUFFIX)
51b5b9
+    m1 = topo_m2.ms["supplier1"]
51b5b9
+    m2 = topo_m2.ms["supplier2"]
51b5b9
+    
51b5b9
+
51b5b9
+    # create a test user
51b5b9
+    testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
51b5b9
+    testuser = UserAccount(m1, testuser_dn)
51b5b9
+    try:
51b5b9
+        testuser.create(properties={
51b5b9
+            'uid': 'testuser',
51b5b9
+            'cn': 'testuser',
51b5b9
+            'sn': 'testuser',
51b5b9
+            'uidNumber' : '1000',
51b5b9
+            'gidNumber' : '2000',
51b5b9
+            'homeDirectory' : '/home/testuser',
51b5b9
+        })
51b5b9
+    except ldap.ALREADY_EXISTS:
51b5b9
+        pass
51b5b9
+    testuser.replace('displayName', 'to trigger replication M1-> M2')
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+    # Stop suppliers to update the schema
51b5b9
+    m1.stop()
51b5b9
+    m2.stop()
51b5b9
+
51b5b9
+    # on M1: gecos is DirectoryString (default)
51b5b9
+    # on M2: gecos is IA5
51b5b9
+    schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+    try:
51b5b9
+        with open(schema_filename, 'w') as schema_file:
51b5b9
+            schema_file.write("dn: cn=schema\n")
51b5b9
+            schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
51b5b9
+                              "'gecos' DESC 'The GECOS field; the common name' " +
51b5b9
+                              "EQUALITY caseIgnoreIA5Match " +
51b5b9
+                              "SUBSTR caseIgnoreIA5SubstringsMatch " +
51b5b9
+                              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
51b5b9
+                              "SINGLE-VALUE )\n")
51b5b9
+        os.chmod(schema_filename, 0o777)
51b5b9
+    except OSError as e:
51b5b9
+        log.fatal("Failed to update schema file: " +
51b5b9
+                  "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+
51b5b9
+    # start the instances
51b5b9
+    m1.start()
51b5b9
+    m2.start()
51b5b9
+
51b5b9
+    # Check that gecos is IA5 on M2
51b5b9
+    schema = SchemaLegacy(m2)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
51b5b9
+
51b5b9
+    # update M2 schema to increase its nsschemaCSN
51b5b9
+    new_at = "( dummy-oid NAME 'dummy' DESC 'dummy attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )"
51b5b9
+    m2.schema.add_schema('attributetypes', ensure_bytes(new_at))
51b5b9
+
51b5b9
+    # update just to trigger replication M2->M1
51b5b9
+    # and update of M2 schema
51b5b9
+    testuser_m2 = UserAccount(m2, testuser_dn)
51b5b9
+    testuser_m2.replace('displayName', 'to trigger replication M2-> M1')
51b5b9
+
51b5b9
+    # Add a gecos UTF value on M1
51b5b9
+    testuser.replace('gecos', 'Hélène')
51b5b9
+
51b5b9
+    # Check replication is still working
51b5b9
+    testuser.replace('displayName', 'ascii value')
51b5b9
+    repl.wait_for_replication(m1, m2)
51b5b9
+    assert testuser_m2.exists()
51b5b9
+    assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
51b5b9
+
51b5b9
+    # Check that gecos is DirectoryString on M1
51b5b9
+    schema = SchemaLegacy(m1)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
51b5b9
+
51b5b9
+    # Check that gecos is DirectoryString on M2
51b5b9
+    schema = SchemaLegacy(m2)
51b5b9
+    attributetypes = schema.query_attributetype('gecos')
51b5b9
+    assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        m1.start()
51b5b9
+        m2.start()
51b5b9
+        testuser.delete()
51b5b9
+        m1.schema.del_schema('attributetypes', ensure_bytes(new_at))
51b5b9
+        repl.wait_for_replication(m1, m2)
51b5b9
+
51b5b9
+        # on M2 restore a default 99user.ldif
51b5b9
+        m2.stop()
51b5b9
+        os.remove(m2.schemadir + "/99user.ldif")
51b5b9
+        schema_filename = (m2.schemadir + "/99user.ldif")
51b5b9
+        try:
51b5b9
+            with open(schema_filename, 'w') as schema_file:
51b5b9
+                schema_file.write("dn: cn=schema\n")
51b5b9
+            os.chmod(schema_filename, 0o777)
51b5b9
+        except OSError as e:
51b5b9
+            log.fatal("Failed to update schema file: " +
51b5b9
+                      "{} Error: {}".format(schema_filename, str(e)))
51b5b9
+        m2.start()
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
 
51b5b9
 if __name__ == '__main__':
51b5b9
     # Run isolated
51b5b9
diff --git a/ldap/schema/10rfc2307compat.ldif b/ldap/schema/10rfc2307compat.ldif
51b5b9
index 8ba72e1e3..998b8983b 100644
51b5b9
--- a/ldap/schema/10rfc2307compat.ldif
51b5b9
+++ b/ldap/schema/10rfc2307compat.ldif
51b5b9
@@ -21,9 +21,9 @@ attributeTypes: (
51b5b9
 attributeTypes: (
51b5b9
   1.3.6.1.1.1.1.2 NAME 'gecos'
51b5b9
   DESC 'The GECOS field; the common name'
51b5b9
-  EQUALITY caseIgnoreIA5Match
51b5b9
-  SUBSTR caseIgnoreIA5SubstringsMatch
51b5b9
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
51b5b9
+  EQUALITY caseIgnoreMatch
51b5b9
+  SUBSTR caseIgnoreSubstringsMatch
51b5b9
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
51b5b9
   SINGLE-VALUE
51b5b9
   )
51b5b9
 attributeTypes: (
51b5b9
-- 
51b5b9
2.31.1
51b5b9