1304 lines · 42.2 KB · Java
RawDownload
/* * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jndi.ldap; import javax.naming.*;import javax.naming.directory.*;import java.util.Hashtable;import java.util.Vector; /** * Netscape's 3.1 servers have some schema bugs: * - It puts quotes around OIDs (such as those for SUP, SYNTAX). * - When you try to write out the MUST/MAY list (such as "MUST cn"), *   it wants ("MUST (cn)") instead */ final class LdapSchemaParser {     // do debugging    private static final boolean debug = false;      // names of attribute IDs in the LDAP schema entry    static final String OBJECTCLASSDESC_ATTR_ID = "objectClasses";    static final String ATTRIBUTEDESC_ATTR_ID = "attributeTypes";    static final String SYNTAXDESC_ATTR_ID = "ldapSyntaxes";    static final String MATCHRULEDESC_ATTR_ID = "matchingRules";     // information for creating internal nodes in JNDI schema tree    static final String OBJECTCLASS_DEFINITION_NAME =                        "ClassDefinition";    private static final String[] CLASS_DEF_ATTRS = {                         "objectclass", "ClassDefinition"};            static final String ATTRIBUTE_DEFINITION_NAME =                        "AttributeDefinition";    private static final String[] ATTR_DEF_ATTRS = {                        "objectclass", "AttributeDefinition" };            static final String SYNTAX_DEFINITION_NAME =                        "SyntaxDefinition";    private static final String[] SYNTAX_DEF_ATTRS = {                        "objectclass", "SyntaxDefinition" };            static final String MATCHRULE_DEFINITION_NAME =                        "MatchingRule";    private static final String[] MATCHRULE_DEF_ATTRS = {                        "objectclass", "MatchingRule" };     // special tokens used in LDAP schema descriptions    private static final char   SINGLE_QUOTE = '\'';    private static final char   WHSP = ' ';    private static final char   OID_LIST_BEGIN = '(';    private static final char   OID_LIST_END = ')';    private static final char   OID_SEPARATOR = '$';     // common IDs    private static final String  NUMERICOID_ID = "NUMERICOID";    private static final String        NAME_ID = "NAME";    private static final String        DESC_ID = "DESC";    private static final String    OBSOLETE_ID = "OBSOLETE";    private static final String         SUP_ID = "SUP";    private static final String     PRIVATE_ID = "X-";     // Object Class specific IDs    private static final String    ABSTRACT_ID = "ABSTRACT";    private static final String  STRUCTURAL_ID = "STRUCTURAL";    private static final String    AUXILARY_ID = "AUXILIARY";    private static final String        MUST_ID = "MUST";    private static final String         MAY_ID = "MAY";     // Attribute Type specific IDs    private static final String    EQUALITY_ID = "EQUALITY";    private static final String    ORDERING_ID = "ORDERING";    private static final String      SUBSTR_ID = "SUBSTR";    private static final String      SYNTAX_ID = "SYNTAX";    private static final String  SINGLE_VAL_ID = "SINGLE-VALUE";    private static final String  COLLECTIVE_ID = "COLLECTIVE";    private static final String NO_USER_MOD_ID = "NO-USER-MODIFICATION";    private static final String       USAGE_ID = "USAGE";     // The string value we give to boolean variables    private static final String SCHEMA_TRUE_VALUE = "true";     // To get around writing schemas that crash Netscape server    private boolean netscapeBug;     LdapSchemaParser(boolean netscapeBug) {        this.netscapeBug = netscapeBug;    }     final static void LDAP2JNDISchema(Attributes schemaAttrs,        LdapSchemaCtx schemaRoot) throws NamingException {        Attribute               objectClassesAttr = null;        Attribute               attributeDefAttr = null;        Attribute               syntaxDefAttr = null;        Attribute               matchRuleDefAttr = null;         objectClassesAttr = schemaAttrs.get(OBJECTCLASSDESC_ATTR_ID);        if(objectClassesAttr != null) {            objectDescs2ClassDefs(objectClassesAttr,schemaRoot);        }         attributeDefAttr = schemaAttrs.get(ATTRIBUTEDESC_ATTR_ID);        if(attributeDefAttr != null) {            attrDescs2AttrDefs(attributeDefAttr, schemaRoot);        }         syntaxDefAttr = schemaAttrs.get(SYNTAXDESC_ATTR_ID);        if(syntaxDefAttr != null) {            syntaxDescs2SyntaxDefs(syntaxDefAttr, schemaRoot);        }         matchRuleDefAttr = schemaAttrs.get(MATCHRULEDESC_ATTR_ID);        if(matchRuleDefAttr != null) {            matchRuleDescs2MatchRuleDefs(matchRuleDefAttr, schemaRoot);        }    }     final private static DirContext objectDescs2ClassDefs(Attribute objDescsAttr,                                                   LdapSchemaCtx schemaRoot)        throws NamingException {         NamingEnumeration       objDescs;        Attributes      objDef;        LdapSchemaCtx   classDefTree;         // create the class def subtree        Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);        attrs.put(CLASS_DEF_ATTRS[0], CLASS_DEF_ATTRS[1]);        classDefTree = schemaRoot.setup(LdapSchemaCtx.OBJECTCLASS_ROOT,            OBJECTCLASS_DEFINITION_NAME, attrs);         objDescs = objDescsAttr.getAll();        String currentName;        while(objDescs.hasMore()) {            String objDesc = (String)objDescs.next();            try {                Object[] def = desc2Def(objDesc);                currentName = (String) def[0];                objDef = (Attributes) def[1];                classDefTree.setup(LdapSchemaCtx.OBJECTCLASS,                    currentName, objDef);            } catch (NamingException ne) {                // error occurred while parsing, ignore current entry            }        }         return classDefTree;    }     final private static DirContext attrDescs2AttrDefs(Attribute attributeDescAttr,                                                LdapSchemaCtx schemaRoot)        throws NamingException {         NamingEnumeration       attrDescs;        Attributes      attrDef;        LdapSchemaCtx   attrDefTree;         // create the AttributeDef subtree        Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);        attrs.put(ATTR_DEF_ATTRS[0], ATTR_DEF_ATTRS[1]);        attrDefTree = schemaRoot.setup(LdapSchemaCtx.ATTRIBUTE_ROOT,            ATTRIBUTE_DEFINITION_NAME, attrs);         attrDescs = attributeDescAttr.getAll();        String currentName;        while(attrDescs.hasMore()) {            String attrDesc = (String)attrDescs.next();            try {                Object[] def = desc2Def(attrDesc);                currentName = (String) def[0];                attrDef = (Attributes) def[1];                attrDefTree.setup(LdapSchemaCtx.ATTRIBUTE,                    currentName, attrDef);            } catch (NamingException ne) {                // error occurred while parsing, ignore current entry            }        }         return attrDefTree;    }     final private static DirContext syntaxDescs2SyntaxDefs(                                                Attribute syntaxDescAttr,                                                LdapSchemaCtx schemaRoot)        throws NamingException {         NamingEnumeration       syntaxDescs;        Attributes      syntaxDef;        LdapSchemaCtx   syntaxDefTree;         // create the SyntaxDef subtree        Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);        attrs.put(SYNTAX_DEF_ATTRS[0], SYNTAX_DEF_ATTRS[1]);        syntaxDefTree = schemaRoot.setup(LdapSchemaCtx.SYNTAX_ROOT,            SYNTAX_DEFINITION_NAME, attrs);         syntaxDescs = syntaxDescAttr.getAll();        String currentName;        while(syntaxDescs.hasMore()) {            String syntaxDesc = (String)syntaxDescs.next();            try {                Object[] def = desc2Def(syntaxDesc);                currentName = (String) def[0];                syntaxDef = (Attributes) def[1];                syntaxDefTree.setup(LdapSchemaCtx.SYNTAX,                    currentName, syntaxDef);            } catch (NamingException ne) {                // error occurred while parsing, ignore current entry            }        }         return syntaxDefTree;    }     final private static DirContext matchRuleDescs2MatchRuleDefs(                                                Attribute matchRuleDescAttr,                                                LdapSchemaCtx schemaRoot)        throws NamingException {         NamingEnumeration       matchRuleDescs;        Attributes      matchRuleDef;        LdapSchemaCtx   matchRuleDefTree;         // create the MatchRuleDef subtree        Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);        attrs.put(MATCHRULE_DEF_ATTRS[0], MATCHRULE_DEF_ATTRS[1]);        matchRuleDefTree = schemaRoot.setup(LdapSchemaCtx.MATCHRULE_ROOT,            MATCHRULE_DEFINITION_NAME, attrs);         matchRuleDescs = matchRuleDescAttr.getAll();        String currentName;        while(matchRuleDescs.hasMore()) {            String matchRuleDesc = (String)matchRuleDescs.next();            try {                Object[] def = desc2Def(matchRuleDesc);                currentName = (String) def[0];                matchRuleDef = (Attributes) def[1];                matchRuleDefTree.setup(LdapSchemaCtx.MATCHRULE,                    currentName, matchRuleDef);            } catch (NamingException ne) {                // error occurred while parsing, ignore current entry            }        }         return matchRuleDefTree;    }     final private static Object[] desc2Def(String desc)        throws NamingException {            //System.err.println(desc);         Attributes      attrs = new BasicAttributes(LdapClient.caseIgnore);        Attribute       attr = null;        int[]           pos = new int[]{1}; // tolerate missing leading space        boolean         moreTags = true;         // Always begins with <whsp numericoid whsp>        attr = readNumericOID(desc, pos);        String currentName = (String) attr.get(0);  // name is OID by default        attrs.put(attr);         skipWhitespace(desc, pos);         while (moreTags) {            attr = readNextTag(desc, pos);            attrs.put(attr);             if (attr.getID().equals(NAME_ID)) {                currentName = (String) attr.get(0);  // use NAME attribute as name            }             skipWhitespace(desc, pos);             if( pos[0] >= desc.length() -1 ) {                moreTags = false;            }        }         return new Object[] {currentName, attrs};    }     // returns the index of the first whitespace char of a linear whitspace    // sequince ending at the given position.    final private static int findTrailingWhitespace(String string, int pos) {        for(int i = pos; i > 0; i--) {            if(string.charAt(i) != WHSP) {                return i + 1;            }        }        return 0;    }     final private static void skipWhitespace(String string, int[] pos) {        for(int i=pos[0]; i < string.length(); i++) {            if(string.charAt(i) != WHSP) {                pos[0] = i;                if (debug) {                    System.err.println("skipWhitespace: skipping to "+i);                }                return;            }        }    }     final private static Attribute readNumericOID(String string, int[] pos)        throws NamingException {         if (debug) {            System.err.println("readNumericoid: pos="+pos[0]);        }         int begin, end;        String value = null;         skipWhitespace(string, pos);         begin = pos[0];        end = string.indexOf(WHSP, begin);         if (end == -1 || end - begin < 1) {            throw new InvalidAttributeValueException("no numericoid found: "                                                     + string);        }         value = string.substring(begin, end);         pos[0] += value.length();         return new BasicAttribute(NUMERICOID_ID, value);    }     final private static Attribute readNextTag(String string, int[] pos)        throws NamingException {         Attribute       attr = null;        String          tagName = null;        String[]        values = null;         skipWhitespace(string, pos);         if (debug) {            System.err.println("readNextTag: pos="+pos[0]);        }         // get the name and values of the attribute to return        int trailingSpace = string.indexOf( WHSP, pos[0] );         // tolerate a schema that omits the trailing space        if (trailingSpace < 0) {            tagName = string.substring( pos[0], string.length() - 1);        } else {            tagName = string.substring( pos[0], trailingSpace );        }         values = readTag(tagName, string, pos);         // make sure at least one value was returned        if(values.length < 0) {            throw new InvalidAttributeValueException("no values for " +                                                     "attribute \"" +                                                     tagName + "\"");        }         // create the attribute, using the first value        attr = new BasicAttribute(tagName, values[0]);         // add other values if there are any        for(int i = 1; i < values.length; i++) {            attr.add(values[i]);        }         return attr;    }     final private static String[] readTag(String tag, String string, int[] pos)        throws NamingException {         if (debug) {            System.err.println("ReadTag: " + tag + " pos="+pos[0]);        }         // move parser past tag name        pos[0] += tag.length();        skipWhitespace(string, pos);         if (tag.equals(NAME_ID)) {            return readQDescrs(string, pos);  // names[0] is NAME        }         if(tag.equals(DESC_ID)) {           return readQDString(string, pos);        }         if (           tag.equals(EQUALITY_ID) ||           tag.equals(ORDERING_ID) ||           tag.equals(SUBSTR_ID) ||           tag.equals(SYNTAX_ID)) {            return readWOID(string, pos);        }         if (tag.equals(OBSOLETE_ID) ||            tag.equals(ABSTRACT_ID) ||            tag.equals(STRUCTURAL_ID) ||            tag.equals(AUXILARY_ID) ||            tag.equals(SINGLE_VAL_ID) ||            tag.equals(COLLECTIVE_ID) ||            tag.equals(NO_USER_MOD_ID)) {            return new String[] {SCHEMA_TRUE_VALUE};        }         if (tag.equals(SUP_ID) ||   // oid list for object class; WOID for attribute            tag.equals(MUST_ID) ||            tag.equals(MAY_ID) ||            tag.equals(USAGE_ID)) {            return readOIDs(string, pos);        }         // otherwise it's a schema element with a quoted string value        return readQDStrings(string, pos);    }     final private static String[] readQDString(String string, int[] pos)        throws NamingException {         int begin, end;         begin = string.indexOf(SINGLE_QUOTE, pos[0]) + 1;        end = string.indexOf(SINGLE_QUOTE, begin);         if (debug) {            System.err.println("ReadQDString: pos=" + pos[0] +                               " begin=" + begin + " end=" + end);        }         if(begin == -1 || end == -1 || begin == end) {            throw new InvalidAttributeIdentifierException("malformed " +                                                          "QDString: " +                                                          string);        }         // make sure the qdstring end symbol is there        if (string.charAt(begin - 1) != SINGLE_QUOTE) {            throw new InvalidAttributeIdentifierException("qdstring has " +                                                          "no end mark: " +                                                          string);        }         pos[0] = end+1;        return new String[] {string.substring(begin, end)};    }    /**    * dstring         = 1*utf8    * qdstring        = whsp "'" dstring "'" whsp    * qdstringlist    = [ qdstring *( qdstring ) ]    * qdstrings       = qdstring / ( whsp "(" qdstringlist ")" whsp )    */    private final static String[] readQDStrings(String string, int[] pos)        throws NamingException {         return readQDescrs(string, pos);    }     /**     * ; object descriptors used as schema element names     * qdescrs         = qdescr / ( whsp "(" qdescrlist ")" whsp )     * qdescrlist      = [ qdescr *( qdescr ) ]     * qdescr          = whsp "'" descr "'" whsp     * descr           = keystring     */    final private static String[] readQDescrs(String string, int[] pos)        throws NamingException {         if (debug) {            System.err.println("readQDescrs: pos="+pos[0]);        } 

Lines 1–500 of 1304.