opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CoreSchemaConfiguration.xml
@@ -18,8 +18,7 @@ extends="schema-provider" package="org.forgerock.opendj.server.config" xmlns:adm="http://opendj.forgerock.org/admin" xmlns:ldap="http://opendj.forgerock.org/admin-ldap" xmlns:cli="http://opendj.forgerock.org/admin-cli"> xmlns:ldap="http://opendj.forgerock.org/admin-ldap"> <adm:synopsis> <adm:user-friendly-name /> define the core schema elements to load. @@ -260,4 +259,41 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="json-validation-policy" advanced="true"> <adm:synopsis> Specifies the policy that will be used when validating JSON syntax values. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>strict</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:enumeration> <adm:value name="disabled"> <adm:synopsis> JSON syntax values will not be validated and, as a result any sequence of bytes will be acceptable. </adm:synopsis> </adm:value> <adm:value name="lenient"> <adm:synopsis> JSON syntax values must comply with RFC 7159 except: 1) comments are allowed, 2) single quotes may be used instead of double quotes, and 3) unquoted control characters are allowed in strings. </adm:synopsis> </adm:value> <adm:value name="strict"> <adm:synopsis> JSON syntax values must strictly conform to RFC 7159. </adm:synopsis> </adm:value> </adm:enumeration> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-json-validation-policy</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/JsonSchemaConfiguration.xml
New file @@ -0,0 +1,160 @@ <?xml version="1.0" encoding="utf-8"?> <!-- The contents of this file are subject to the terms of the Common Development and Distribution License (the License). You may not use this file except in compliance with the License. You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the specific language governing permission and limitations under the License. When distributing Covered Software, include this CDDL Header Notice in each file and include the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL Header, with the fields enclosed by brackets [] replaced by your own identifying information: "Portions copyright [year] [name of copyright owner]". Copyright 2016 ForgeRock AS. --> <adm:managed-object name="json-schema" plural-name="json-schemas" extends="schema-provider" package="org.forgerock.opendj.server.config" xmlns:adm="http://opendj.forgerock.org/admin" xmlns:ldap="http://opendj.forgerock.org/admin-ldap"> <adm:synopsis> The JSON Schema Provider provides the ability to configure customized JSON query matching rules. </adm:synopsis> <adm:description> The core schema provides a default 'jsonQueryMatch' equality matching rule for JSON values which match JSON strings according to the LDAP 'caseIgnoreMatch' semantics (i.e trim white space and ignore case differences), as well as the indexing of all JSON fields. This schema provider allows users to create custom JSON matching rules which may use different string matching semantics and, more importantly, may only index a restricted set of JSON fields, thereby consuming less backend resources. </adm:description> <adm:profile name="ldap"> <ldap:object-class> <ldap:name>ds-cfg-json-schema</ldap:name> <ldap:superior>ds-cfg-schema-provider</ldap:superior> </ldap:object-class> </adm:profile> <adm:property-override name="java-class" advanced="true"> <adm:default-behavior> <adm:defined> <adm:value> org.opends.server.schema.JsonSchemaProvider </adm:value> </adm:defined> </adm:default-behavior> </adm:property-override> <adm:property name="matching-rule-oid" mandatory="true"> <adm:synopsis> The numeric OID of the custom JSON matching rule. </adm:synopsis> <adm:syntax> <adm:string> <adm:pattern> <adm:regex>^([0-9.]+\\d)$</adm:regex> <adm:usage>OID</adm:usage> <adm:synopsis> The OID of the matching rule. </adm:synopsis> </adm:pattern> </adm:string> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-matching-rule-oid</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="matching-rule-name"> <adm:synopsis> The name of the custom JSON matching rule. </adm:synopsis> <adm:default-behavior> <adm:alias> <adm:synopsis>The matching rule will not have a name.</adm:synopsis> </adm:alias> </adm:default-behavior> <adm:syntax> <adm:string /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-matching-rule-name</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="case-sensitive-strings"> <adm:synopsis> Indicates whether JSON string comparisons should be case-sensitive. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value>false</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:boolean /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-case-sensitive-strings</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="ignore-white-space"> <adm:synopsis> Indicates whether JSON string comparisons should ignore white-space. </adm:synopsis> <adm:description> When enabled all leading and trailing white space will be removed and intermediate white space will be reduced to a single character. </adm:description> <adm:default-behavior> <adm:defined> <adm:value>true</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:boolean /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-ignore-white-space</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="indexed-field" multi-valued="true"> <adm:synopsis> Specifies which JSON fields should be indexed. </adm:synopsis> <adm:description> A field will be indexed if it matches any of the configured field patterns. </adm:description> <adm:default-behavior> <adm:alias> <adm:synopsis>All JSON fields will be indexed.</adm:synopsis> </adm:alias> </adm:default-behavior> <adm:syntax> <adm:string> <adm:pattern> <adm:regex>.*</adm:regex> <adm:usage>PATTERN</adm:usage> <adm:synopsis> A JSON pointer which may include wild-cards. A single '*' wild-card matches at most a single path element, whereas a double '**' matches zero or more path elements. </adm:synopsis> </adm:pattern> </adm:string> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-indexed-field</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opendj-server-legacy/resource/schema/02-config.ldif
@@ -3962,12 +3962,47 @@ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.196 NAME 'ds-cfg-json-validation-policy' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.197 NAME 'ds-cfg-matching-rule-oid' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.198 NAME 'ds-cfg-matching-rule-name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.199 NAME 'ds-cfg-case-sensitive-strings' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.200 NAME 'ds-cfg-ignore-white-space' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.201 NAME 'ds-cfg-show-subordinate-naming-contexts' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.202 NAME 'ds-cfg-indexed-field' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top @@ -6038,3 +6073,13 @@ MAY ( ds-cfg-rotation-policy $ ds-cfg-retention-policy ) X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.53 NAME 'ds-cfg-json-schema' SUP ds-cfg-schema-provider STRUCTURAL MUST ds-cfg-matching-rule-oid MAY ( ds-cfg-matching-rule-name $ ds-cfg-case-sensitive-strings $ ds-cfg-ignore-white-space $ ds-cfg-indexed-field ) X-ORIGIN 'OpenDJ Directory Server' ) opendj-server-legacy/src/main/java/org/opends/server/schema/CoreSchemaProvider.java
@@ -16,6 +16,10 @@ package org.opends.server.schema; import static org.forgerock.opendj.ldap.schema.SchemaOptions.*; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.VALIDATION_POLICY; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.ValidationPolicy.DISABLED; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.ValidationPolicy.LENIENT; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.ValidationPolicy.STRICT; import java.util.List; @@ -76,6 +80,19 @@ .setOption(ALLOW_NON_STANDARD_TELEPHONE_NUMBERS, !configuration.isStrictFormatTelephoneNumbers()) .setOption(ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX, configuration.isAllowAttributeTypesWithNoSupOrSyntax()); switch (configuration.getJsonValidationPolicy()) { case DISABLED: schemaBuilder.setOption(VALIDATION_POLICY, DISABLED); break; case LENIENT: schemaBuilder.setOption(VALIDATION_POLICY, LENIENT); break; case STRICT: schemaBuilder.setOption(VALIDATION_POLICY, STRICT); break; } for (final String oid : configuration.getDisabledMatchingRule()) { if (!oid.equals(NONE_ELEMENT)) opendj-server-legacy/src/main/java/org/opends/server/schema/JsonSchemaProvider.java
New file @@ -0,0 +1,152 @@ /* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. */ package org.opends.server.schema; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.CASE_SENSITIVE_STRINGS; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.IGNORE_WHITE_SPACE; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.INDEXED_FIELD_PATTERNS; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.newJsonQueryEqualityMatchingRuleImpl; import static org.forgerock.util.Options.defaultOptions; import java.util.List; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.config.server.ConfigChangeResult; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.config.server.ConfigurationChangeListener; import org.forgerock.opendj.ldap.schema.MatchingRule; import org.forgerock.opendj.ldap.schema.MatchingRuleImpl; import org.forgerock.opendj.ldap.schema.SchemaBuilder; import org.forgerock.opendj.rest2ldap.schema.JsonSchema; import org.forgerock.opendj.server.config.server.JsonSchemaCfg; import org.forgerock.util.Options; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ServerContext; import org.opends.server.schema.SchemaHandler.SchemaUpdater; import org.opends.server.types.DirectoryException; import org.opends.server.types.InitializationException; /** Allows users to configure custom JSON matching rules and indexing. */ public class JsonSchemaProvider implements SchemaProvider<JsonSchemaCfg>, ConfigurationChangeListener<JsonSchemaCfg> { /** The current configuration of JSON schema. */ private JsonSchemaCfg currentConfig; private ServerContext serverContext; @Override public void initialize(final ServerContext serverContext, final JsonSchemaCfg configuration, final SchemaBuilder initialSchemaBuilder) throws ConfigException, InitializationException { this.serverContext = serverContext; this.currentConfig = configuration; addCustomJsonMatchingRule(initialSchemaBuilder, configuration); currentConfig.addJsonSchemaChangeListener(this); } private void addCustomJsonMatchingRule(final SchemaBuilder schemaBuilder, final JsonSchemaCfg configuration) { if (!configuration.isEnabled()) { return; } final String nameOrOid = configuration.getMatchingRuleName() != null ? configuration.getMatchingRuleName() : configuration.getMatchingRuleOid(); final Options options = defaultOptions().set(CASE_SENSITIVE_STRINGS, configuration.isCaseSensitiveStrings()) .set(IGNORE_WHITE_SPACE, configuration.isIgnoreWhiteSpace()) .set(INDEXED_FIELD_PATTERNS, configuration.getIndexedField()); final MatchingRuleImpl matchingRuleImpl = newJsonQueryEqualityMatchingRuleImpl(nameOrOid, options); final MatchingRule.Builder builder = schemaBuilder.buildMatchingRule(configuration.getMatchingRuleOid()) .syntaxOID(JsonSchema.getJsonQuerySyntax().getOID()) .implementation(matchingRuleImpl); if (configuration.getMatchingRuleName() != null) { builder.names(configuration.getMatchingRuleName()); } // Let users overwrite core matching rule definitions in order to control indexing. builder.addToSchemaOverwrite(); } @Override public void finalizeProvider() { if (currentConfig.isEnabled()) { try { serverContext.getSchemaHandler().updateSchema(new SchemaUpdater() { @Override public void update(SchemaBuilder builder) { builder.removeMatchingRule(currentConfig.getMatchingRuleOid()); } }); } catch (DirectoryException e) { // Ignore. } } currentConfig.removeJsonSchemaChangeListener(this); } @Override public boolean isConfigurationAcceptable(final JsonSchemaCfg configuration, final List<LocalizableMessage> unacceptableReasons) { return isConfigurationChangeAcceptable(configuration, unacceptableReasons); } @Override public boolean isConfigurationChangeAcceptable(final JsonSchemaCfg configuration, final List<LocalizableMessage> unacceptableReasons) { return true; } @Override public ConfigChangeResult applyConfigurationChange(final JsonSchemaCfg configuration) { final ConfigChangeResult ccr = new ConfigChangeResult(); try { serverContext.getSchemaHandler().updateSchema(new SchemaUpdater() { @Override public void update(SchemaBuilder builder) { if (currentConfig.isEnabled()) { builder.removeMatchingRule(currentConfig.getMatchingRuleOid()); } addCustomJsonMatchingRule(builder, configuration); } }); } catch (DirectoryException e) { ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(e.getMessageObject()); } finally { currentConfig = configuration; } return ccr; } } opendj-server-legacy/src/main/java/org/opends/server/schema/SchemaHandler.java
@@ -15,6 +15,7 @@ */ package org.opends.server.schema; import static org.forgerock.opendj.rest2ldap.schema.JsonSchema.addJsonSyntaxesAndMatchingRulesToSchema; import static org.opends.server.util.SchemaUtils.is02ConfigLdif; import static java.util.Collections.emptyList; @@ -209,10 +210,10 @@ // Start from the core schema final SchemaBuilder schemaBuilder = new SchemaBuilder(Schema.getCoreSchema()); loadSchemaFromProviders(serverContext.getRootConfig(), schemaBuilder); // Load core syntaxes and matching rules first then let providers adjust them if needed. addServerSyntaxesAndMatchingRules(schemaBuilder); loadSchemaFromProviders(serverContext.getRootConfig(), schemaBuilder); loadSchemaFromFiles(schemaBuilder); try @@ -244,6 +245,7 @@ addHistoricalCsnOrderingMatchingRule(schemaBuilder); addAuthPasswordEqualityMatchingRule(schemaBuilder); addUserPasswordEqualityMatchingRule(schemaBuilder); addJsonSyntaxesAndMatchingRulesToSchema(schemaBuilder); } catch (ConflictingSchemaElementException e) { @@ -705,8 +707,6 @@ * The root to retrieve schema provider configurations. * @param schemaBuilder * The schema builder that providers should update. * @param schemaUpdater * The updater that providers should use when applying a configuration change. */ private void loadSchemaFromProviders(final RootCfg rootConfiguration, final SchemaBuilder schemaBuilder) throws ConfigException, InitializationException {