All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.scim.ldap.ResourceMapper Maven / Gradle / Ivy

/*
 * Copyright 2011-2019 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */

package com.unboundid.scim.ldap;

import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.Modification;
import com.unboundid.ldap.sdk.ModificationType;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
import com.unboundid.scim.data.AttributeValueResolver;
import com.unboundid.scim.schema.AttributeDescriptor;
import com.unboundid.scim.schema.CoreSchema;
import com.unboundid.scim.schema.ResourceDescriptor;
import com.unboundid.scim.sdk.AttributePath;
import com.unboundid.scim.sdk.Debug;
import com.unboundid.scim.sdk.DebugType;
import com.unboundid.scim.sdk.ForbiddenException;
import com.unboundid.scim.sdk.InvalidResourceException;
import com.unboundid.scim.sdk.PreconditionFailedException;
import com.unboundid.scim.sdk.ResourceConflictException;
import com.unboundid.scim.sdk.ResourceNotFoundException;
import com.unboundid.scim.sdk.SCIMAttribute;
import com.unboundid.scim.sdk.SCIMAttributeValue;
import com.unboundid.scim.sdk.SCIMConstants;
import com.unboundid.scim.sdk.SCIMException;
import com.unboundid.scim.sdk.SCIMFilter;
import com.unboundid.scim.sdk.SCIMFilterType;
import com.unboundid.scim.sdk.SCIMObject;
import com.unboundid.scim.sdk.SCIMQueryAttributes;
import com.unboundid.scim.sdk.ServerErrorException;
import com.unboundid.scim.sdk.SortParameters;
import com.unboundid.scim.sdk.StaticUtils;
import com.unboundid.scim.sdk.UnauthorizedException;
import com.unboundid.util.Validator;
import org.xml.sax.SAXException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;

import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;


/**
 * Resource mappers may be used to override the behaviour of any part of the
 * mapping process, which includes:
 * 
    *
  • Retrieve the set of LDAP attribute types that should be requested in * order to return the specified query attributes.
  • *
  • Mapping a SCIM filter to a LDAP filter
  • *
  • Mapping a SCIM filter component to an LDAP filter component
  • *
  • Mapping the attributes in a SCIM object to LDAP attributes
  • *
  • Getting the search base DN to be used for querying
  • *
  • Mapping a set of SCIM sort parameters to a LDAP sort control
  • *
  • Mapping the attributes in a LDAP entry to SCIM attributes
  • *
  • Mapping an LDAP entry to a SCIM resource
  • *
  • Mapping the replacement attributes in a SCIM object to LDAP * modifications
  • *
  • Constructing an LDAP entry from the provided SCIM object.
  • *
*

* Resource mappers should be used to handle situations that are too complex to * be expressed in the configuration file and can not be implemented using * custom attribute value transformations and/or attribute derivations. *

* To use a custom resource mapper class, use the mapper attribute to * specify the implementation class in any resource configuration * elements. For example: *

*
 * <resource name="User"
 *  schema="urn:scim:schemas:core:1.0"
 *  mapper="com.unboundid.example.ExampleResourceMapper"
 * />
 * 
*

* This API is volatile and could change in future releases. */ public class ResourceMapper { /** * The ResourceDescriptor of the SCIM resource handled by this resource * mapper. */ protected ResourceDescriptor resourceDescriptor; /** * The LDAPSearchResolver to resolve resources handled by this resource * manager. */ protected LDAPSearchResolver searchResolver; /** * The LDAP Add parameters. */ protected LDAPAddParameters addParameters; /** * A DN constructed value for the DN template. */ protected ConstructedValue dnConstructor; /** * The attribute mappers for this resource mapper. */ protected Map attributeMappers; /** * The derived attributes for this resource mapper. */ protected Map derivedAttributes; /** * The internal AttributeMapper for the Meta object. This allows the * toLDAPFilter() code to generate LDAP filters which are based on the meta * information, even though there are no explicit mappings for Meta set up in * resources.xml. */ protected AttributeMapper metaAttributeMapper; /** * The internal AttributeMapper for the id attribute. This allows the * toLDAPFilter() code to generate LDAP filters which are based on the id * information, even though there are no explicit mappings for id set up in * resources.xml. */ protected AttributeMapper idAttributeMapper; /** * The internal AttributeMapper for the password attribute. This allows a * caller to determine which LDAP attribute is mapped to the SCIM password * attribute, if any. */ protected AttributeMapper passwordAttributeMapper; /** * Create a new instance of this resource mapper. All resource mappers must * provide a default constructor, but any initialization should be done * in the {@code initializeMapper()} method. */ protected ResourceMapper() { // No implementation required. } /** * Parse an XML file defining a set of resource mappings. The LDAP attribute * mappings are not validated against an LDAP schema. * * @param file An XML file defining a set of resource mappings. * * @return A list of resource mappers. * * @throws JAXBException If an error occurs during the parsing. * @throws SAXException If the XML schema cannot be instantiated. * @throws SCIMException If some other error occurs. */ public static List parse(final File file) throws JAXBException, SAXException, SCIMException { return parse(file, null); } /** * Parse an XML file defining a set of resource mappings. * * @param file An XML file defining a set of resource mappings. * @param ldapSchema An LDAP schema to validate the LDAP attribute mappings * against. This parameter may be {@code null} if LDAP * schema validation is not required. * * @return A list of resource mappers. * * @throws JAXBException If an error occurs during the parsing. * @throws SAXException If the XML schema cannot be instantiated. * @throws SCIMException If some other error occurs. */ public static List parse( final File file, final com.unboundid.ldap.sdk.schema.Schema ldapSchema) throws JAXBException, SAXException, SCIMException { final ObjectFactory factory = new ObjectFactory(); final String packageName = factory.getClass().getPackage().getName(); // Use the class loader that loaded this class to find the JAXB classes. final JAXBContext context = JAXBContext.newInstance(packageName, ResourceMapper.class.getClassLoader()); final Unmarshaller unmarshaller = context.createUnmarshaller(); final URL url = ResourcesDefinition.class.getResource("resources.xsd"); if (url != null) { final SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); final Schema schema = sf.newSchema(url); unmarshaller.setSchema(schema); } final JAXBElement jaxbElement = (JAXBElement) unmarshaller.unmarshal(file); final ResourcesDefinition resources = (ResourcesDefinition)jaxbElement.getValue(); final Map ldapSearchResolvers = new HashMap(); for (final LDAPSearchParameters p : resources.getLDAPSearch()) { if (p.getResourceIDMapping() != null) { if (ldapSchema != null) { final String ldapAttribute = p.getResourceIDMapping().getLdapAttribute(); if (ldapSchema.getAttributeType(ldapAttribute) == null) { throw new ServerErrorException( "The LDAP attribute '" + ldapAttribute + "' referenced in " + "LDAP Search Parameters '" + p.getId() + "' does not exist " + "in the LDAP schema"); } } } try { ldapSearchResolvers.put(StaticUtils.toLowerCase(p.getId()), new LDAPSearchResolver(p, Collections.emptySet())); } catch (LDAPException e) { Debug.debugException(e); throw new ServerErrorException(e.getMessage()); } } final List resourceMappers = new ArrayList(); for (final ResourceDefinition resource : resources.getResource()) { final LDAPSearchParameters ldapSearch; Object o = resource.getLDAPSearchRef().getIdref(); if(o != null) { ldapSearch = (LDAPSearchParameters) o; } else { throw new JAXBException( "Cannot find element referenced by " + "the \"" + resource.getName() + "\" resource."); } final List attributeMappers = new ArrayList(); final List derivedAttributes = new ArrayList(); final List attributeDescriptors = new ArrayList(resource.getAttribute().size() + 2); attributeDescriptors.add(CoreSchema.ID_DESCRIPTOR); attributeDescriptors.add(CoreSchema.META_DESCRIPTOR); for (final AttributeDefinition attributeDefinition : resource.getAttribute()) { final AttributeDescriptor attributeDescriptor = createAttributeDescriptor(attributeDefinition); if (attributeDescriptor.equals(CoreSchema.ID_DESCRIPTOR)) { throw new ServerErrorException( "An attribute definition is not permitted for the 'id' " + "attribute. The mapping for this attribute may only be " + "specified in a LDAPSearch element."); } final AttributeMapper m = AttributeMapper.create(attributeDefinition, attributeDescriptor, ldapSchema); if (m != null) { attributeMappers.add(m); } if (attributeDefinition.getDerivation() != null) { final DerivedAttribute derivedAttribute = DerivedAttribute.create( attributeDefinition.getDerivation().getJavaClass(), attributeDefinition.getDerivation().getAny()); if(derivedAttribute instanceof MembersDerivedAttribute || derivedAttribute instanceof GroupsDerivedAttribute) { if(derivedAttribute.getArguments().containsKey( DerivedAttribute.LDAP_SEARCH_REF)) { String id = derivedAttribute.getArguments().get( DerivedAttribute.LDAP_SEARCH_REF).toString(); final LDAPSearchResolver resolver = ldapSearchResolvers.get(StaticUtils.toLowerCase(id)); if (resolver != null) { //Replace the String in the arguments map with a //LDAPSearchResolver instance. The DerivedAttribute //initialize() method will take advantage of this. derivedAttribute.getArguments().put( DerivedAttribute.LDAP_SEARCH_REF, resolver); } else { throw new JAXBException( "Cannot find element with id=\"" + id + "\"," + "which is referenced by a Derived Attribute (" + derivedAttribute.getClass().getName() + ")"); } } } derivedAttribute.initialize(attributeDescriptor); derivedAttributes.add(derivedAttribute); } // Only include the attribute descriptor if there is a mapping or it is // derived. if(m != null || attributeDefinition.getDerivation() != null) { attributeDescriptors.add(attributeDescriptor); } else { Debug.debug(Level.WARNING, DebugType.OTHER, "Definition for attribute " + new AttributePath( attributeDefinition.getSchema(), attributeDefinition.getName(), null).toString() + " skipped because it does not have a mapping or " + "derivation defined."); } } final ResourceDescriptor resourceDescriptor = ResourceDescriptor.create(resource.getName(), resource.getDescription(), resource.getSchema(), resource.getEndpoint(), attributeDescriptors.toArray( new AttributeDescriptor[attributeDescriptors.size()])); final ResourceMapper resourceMapper = create(resource.getMapping()); final LDAPSearchResolver ldapSearchResolver = ldapSearchResolvers.get(StaticUtils.toLowerCase(ldapSearch.getId())); if (resource.getLDAPAdd() != null) { if (ldapSchema != null) { for (final FixedAttribute fixedAttribute : resource.getLDAPAdd().getFixedAttribute()) { final String ldapAttribute = fixedAttribute.getLdapAttribute(); if (ldapSchema.getAttributeType(ldapAttribute) == null) { throw new ServerErrorException( "The LDAP attribute '" + ldapAttribute + "' referenced by " + "a fixedAttribute element is not defined in the LDAP schema"); } } } } resourceMapper.initializeMapper( resourceDescriptor, ldapSearchResolver, resource.getLDAPAdd(), attributeMappers, derivedAttributes); resourceMappers.add(resourceMapper); } return resourceMappers; } /** * Create an attribute descriptor from an attribute definition. * * @param attributeDefinition The attribute definition. * * @return A new attribute descriptor. * * @throws com.unboundid.scim.sdk.SCIMException If an error occurs. */ private static AttributeDescriptor createAttributeDescriptor( final AttributeDefinition attributeDefinition) throws SCIMException { final String schema = attributeDefinition.getSchema(); if (attributeDefinition.getSimple() != null) { final SimpleAttributeDefinition simpleDefinition = attributeDefinition.getSimple(); return AttributeDescriptor.createAttribute( attributeDefinition.getName(), AttributeDescriptor.DataType.parse( simpleDefinition.getDataType().value()), attributeDefinition.getDescription(), schema, attributeDefinition.isReadOnly(), attributeDefinition.isRequired(), simpleDefinition.isCaseExact()); } else if (attributeDefinition.getComplex() != null) { final ComplexAttributeDefinition complexDefinition = attributeDefinition.getComplex(); final AttributeDescriptor[] subAttributes = new AttributeDescriptor[complexDefinition.getSubAttribute().size()]; int i = 0; for (final SubAttributeDefinition subAttributeDefinition : complexDefinition.getSubAttribute()) { subAttributes[i++] = AttributeDescriptor.createSubAttribute( subAttributeDefinition.getName(), AttributeDescriptor.DataType.parse( subAttributeDefinition.getDataType().value()), subAttributeDefinition.getDescription(), schema, subAttributeDefinition.isReadOnly(), subAttributeDefinition.isRequired(), subAttributeDefinition.isCaseExact()); } return AttributeDescriptor.createAttribute( attributeDefinition.getName(), AttributeDescriptor.DataType.COMPLEX, attributeDefinition.getDescription(), schema, attributeDefinition.isReadOnly(), attributeDefinition.isRequired(), false, subAttributes); } else if (attributeDefinition.getSimpleMultiValued() != null) { final SimpleMultiValuedAttributeDefinition simpleMultiValuedDefinition = attributeDefinition.getSimpleMultiValued(); final String[] canonicalValues = new String[simpleMultiValuedDefinition.getCanonicalValue().size()]; int i = 0; for (final CanonicalValue CanonicalValue : simpleMultiValuedDefinition.getCanonicalValue()) { canonicalValues[i++] = CanonicalValue.getName(); } AttributeDescriptor.DataType dataType = AttributeDescriptor.DataType.parse( simpleMultiValuedDefinition.getDataType().value()); if(canonicalValues.length > 0) { return AttributeDescriptor.createMultiValuedAttribute( attributeDefinition.getName(), simpleMultiValuedDefinition.getChildName(), attributeDefinition.getDescription(), schema, attributeDefinition.isReadOnly(), attributeDefinition.isRequired(), simpleMultiValuedDefinition.isCaseExact(), CoreSchema.createMultiValuedValueDescriptor(schema, dataType), CoreSchema.createMultiValuedTypeDescriptor(schema, canonicalValues)); } else { return AttributeDescriptor.createMultiValuedAttribute( attributeDefinition.getName(), simpleMultiValuedDefinition.getChildName(), attributeDefinition.getDescription(), schema, attributeDefinition.isReadOnly(), attributeDefinition.isRequired(), simpleMultiValuedDefinition.isCaseExact(), CoreSchema.createMultiValuedValueDescriptor(schema, dataType)); } } else if (attributeDefinition.getComplexMultiValued() != null) { final ComplexMultiValuedAttributeDefinition complexMultiValuedDefinition = attributeDefinition.getComplexMultiValued(); final String[] canonicalValues = new String[complexMultiValuedDefinition.getCanonicalValue().size()]; int i = 0; for (final CanonicalValue CanonicalValue : complexMultiValuedDefinition.getCanonicalValue()) { canonicalValues[i++] = CanonicalValue.getName(); } AttributeDescriptor[] subAttributes = new AttributeDescriptor[ complexMultiValuedDefinition.getSubAttribute().size()]; i = 0; if(canonicalValues.length > 0) { subAttributes = new AttributeDescriptor[ complexMultiValuedDefinition.getSubAttribute().size() + 1]; subAttributes[ complexMultiValuedDefinition.getSubAttribute().size()] = CoreSchema.createMultiValuedTypeDescriptor(schema, canonicalValues); } for (final SubAttributeDefinition subAttributeDefinition : complexMultiValuedDefinition.getSubAttribute()) { subAttributes[i++] = AttributeDescriptor.createSubAttribute( subAttributeDefinition.getName(), AttributeDescriptor.DataType.parse( subAttributeDefinition.getDataType().value()), subAttributeDefinition.getDescription(), schema, subAttributeDefinition.isReadOnly(), subAttributeDefinition.isRequired(), subAttributeDefinition.isCaseExact()); } return AttributeDescriptor.createMultiValuedAttribute( attributeDefinition.getName(), complexMultiValuedDefinition.getChildName(), attributeDefinition.getDescription(), schema, attributeDefinition.isReadOnly(), attributeDefinition.isRequired(), false, subAttributes); } else { final SCIMException e = new ServerErrorException( "Attribute definition '" + attributeDefinition.getName() + "' does not have a simple, complex, simpleMultiValued or " + "complexMultiValued element"); Debug.debugCodingError(e); throw e; } } /** * Initialize this resource mapper from the provided information. * * @param resourceDescriptor The ResourceDescriptor of the SCIM resource * handled by this resource mapper. * @param searchResolver The LDAP Search resolver. * @param addParameters The LDAP Add parameters, or {@code null} if there * are none defined. * @param mappers The attribute mappers for this resource mapper. * @param derivedAttributes The derived attributes for this resource mapper. */ public void initializeMapper( final ResourceDescriptor resourceDescriptor, final LDAPSearchResolver searchResolver, final LDAPAddParameters addParameters, final Collection mappers, final Collection derivedAttributes) { this.resourceDescriptor = resourceDescriptor; this.addParameters = addParameters; this.searchResolver = searchResolver; if (addParameters != null) { this.dnConstructor = new ConstructedValue(addParameters.getDNTemplate().trim()); } else { this.dnConstructor = null; } metaAttributeMapper = createMetaAttributeMapper(); idAttributeMapper = searchResolver.getIdAttributeMapper(); attributeMappers = new HashMap(mappers.size()); for (final AttributeMapper m : mappers) { attributeMappers.put(m.getAttributeDescriptor(), m); if (m instanceof PasswordAttributeMapper) { passwordAttributeMapper = m; } } this.derivedAttributes = new HashMap( derivedAttributes.size()); for (final DerivedAttribute derivedAttribute : derivedAttributes) { this.derivedAttributes.put(derivedAttribute.getAttributeDescriptor(), derivedAttribute); } } /** * Performs any cleanup which may be necessary when this resource mapper is * to be taken out of service. */ public void finalizeMapper() { // No implementation required. } /** * Retrieve the ResourceDescriptor of the SCIM resource handled by this * resource mapper. * * @return The ResourceDescriptor of the SCIM resource handled by this * resource mapper. */ public ResourceDescriptor getResourceDescriptor() { return resourceDescriptor; } /** * Gets the default schema URI that is assumed by this ResourceMapper. * Typically this should be the SCIM Core Schema, but subclasses may choose * to override this. * * @return a SCIM schema URN. */ public String getDefaultSchemaURI() { return SCIMConstants.SCHEMA_URI_CORE; } /** * Indicates whether this mapper supports querying of resources. * * @return {@code true} if this mapper supports resource query. */ public boolean supportsQuery() { return searchResolver != null; } /** * Indicates whether this mapper supports creation of new resources through * {@code toLDAPEntry}. * * @return {@code true} if this mapper supports resource creation. */ public boolean supportsCreate() { return addParameters != null; } /** * Retrieve the set of LDAP attribute types that should be requested in order * to return the specified query attributes. Any LDAP attribute types mapped * from the password attribute will not be included. * * @param queryAttributes The requested query attributes. * * @return The set of LDAP attribute types that should be requested. */ public Set toLDAPAttributeTypes( final SCIMQueryAttributes queryAttributes) { final Set ldapAttributes = new HashSet(); for (final AttributeMapper m : attributeMappers.values()) { if (queryAttributes.isAttributeRequested(m.getAttributeDescriptor()) && !(m instanceof PasswordAttributeMapper)) { ldapAttributes.addAll(m.getLDAPAttributeTypes()); } } for (final Map.Entry e : derivedAttributes.entrySet()) { if (queryAttributes.isAttributeRequested(e.getKey())) { final DerivedAttribute derivedAttribute = e.getValue(); ldapAttributes.addAll(derivedAttribute.getLDAPAttributeTypes()); } } searchResolver.addIdAttribute(ldapAttributes); if (queryAttributes.isDebugSearchIndex()) { ldapAttributes.add("debugsearchindex"); } return ldapAttributes; } /** * Retrieve the set of LDAP attribute types that are mapped from the given * set of SCIM attributes. * * @param scimAttributes The SCIM attributes to map. * * @return The set of LDAP attribute types that are derived from the given * SCIM attributes. * @throws InvalidResourceException if the SCIM attributes contains an * undefined attribute. */ protected Set toLDAPAttributeTypes( final Set scimAttributes) throws InvalidResourceException { final Set ldapAttributes = new LinkedHashSet(); for(AttributePath scimAttribute : scimAttributes) { final AttributeDescriptor attributeDescriptor = resourceDescriptor.getAttribute( scimAttribute.getAttributeSchema(), scimAttribute.getAttributeName()); AttributeMapper attributeMapper = attributeMappers.get(attributeDescriptor); if (attributeMapper != null) { ldapAttributes.addAll( attributeMapper.toLDAPAttributeTypes(scimAttribute)); } DerivedAttribute derivedAttribute = derivedAttributes.get(attributeDescriptor); if (derivedAttribute != null) { ldapAttributes.addAll( derivedAttribute.toLDAPAttributeTypes(scimAttribute)); } } return ldapAttributes; } /** * Construct an LDAP entry from the provided SCIM object. This method, which * does not need an LDAP interface argument, is provided for the Sync Server * SCIM Sync Destination. * * @param scimObject The SCIM object to form the contents of the entry. * * @return An LDAP entry. * * @throws SCIMException If the entry could not be constructed. */ public Entry toLDAPEntry(final SCIMObject scimObject) throws SCIMException { return toLDAPEntry(scimObject, null); } /** * Construct an LDAP entry from the provided SCIM object. * * @param scimObject The SCIM object to form the contents of the entry. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return An LDAP entry. * * @throws SCIMException If the entry could not be constructed. */ public Entry toLDAPEntry(final SCIMObject scimObject, final LDAPRequestInterface ldapInterface) throws SCIMException { Entry entry = new Entry(""); if (addParameters == null) { throw new RuntimeException( "No LDAP Add Parameters were specified for the " + resourceDescriptor.getName() + " Resource Mapper"); } for (final FixedAttribute fixedAttribute : addParameters.getFixedAttribute()) { boolean preserveExisting = false; final String attributeName = fixedAttribute.getLdapAttribute(); if (entry.hasAttribute(attributeName)) { switch (fixedAttribute.getOnConflict()) { case MERGE: break; case OVERWRITE: entry.removeAttribute(attributeName); break; case PRESERVE: preserveExisting = true; break; } } if (!preserveExisting) { entry.addAttribute( new Attribute(attributeName, fixedAttribute.getFixedValue())); } } for (final Attribute a : toLDAPAttributes(scimObject, ldapInterface)) { entry.addAttribute(a); } // TODO allow SCIM object values to be referenced entry.setDN(constructEntryDN(entry)); entry = searchResolver.preProcessAddEntry(entry); return entry; } /** * Map the attributes in a SCIM object to LDAP attributes. * * @param scimObject The object containing attributes to be mapped. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A list of LDAP attributes mapped from the SCIM object. This should * never be {@code null} but may be empty. * * @throws SCIMException If the attributes could not be mapped. */ public List toLDAPAttributes( final SCIMObject scimObject, final LDAPRequestInterface ldapInterface) throws SCIMException { final List attributes = new ArrayList(); if (ldapInterface != null) { for (final Map.Entry e : derivedAttributes.entrySet()) { final DerivedAttribute derivedAttribute = e.getValue(); derivedAttribute.toLDAPAttributes(scimObject, attributes, ldapInterface, searchResolver); } } for (final AttributeMapper attributeMapper : attributeMappers.values()) { attributeMapper.toLDAPAttributes(scimObject, attributes); } return attributes; } /** * Retrieve the set of all modifiable LDAP attribute types that should be * requested in order to return the current LDAP entry representing the SCIM * object. This entry may then be used with {@code toLDAPModifications} to * map the replacement attributes to LDAP modifications. * * @param scimObject The object containing attributes to be mapped. * @return The set of LDAP attribute types that should be requested. * @throws InvalidResourceException if the SCIM attributes contains an * undefined attribute. */ public Set getModifiableLDAPAttributeTypes( final SCIMObject scimObject) throws InvalidResourceException { final Set ldapAttributeTypes = new TreeSet(String.CASE_INSENSITIVE_ORDER); final boolean hasPasswordAttribute = scimObject.hasAttribute(SCIMConstants.SCHEMA_URI_CORE, "password"); // Retrieve all LDAP attributes that are mapped from SCIM attributes. for (final AttributeMapper m : attributeMappers.values()) { // Exclude read only SCIM attributes, and passwords in some cases. // The password attribute is a special case as it should not be retrieved // unless it is included in the updated SCIM object to be mapped. if(!m.getAttributeDescriptor().isReadOnly() && (hasPasswordAttribute || !(m instanceof PasswordAttributeMapper))) { ldapAttributeTypes.addAll(m.getLDAPAttributeTypes()); } } for (final Map.Entry e : derivedAttributes.entrySet()) { if (!e.getKey().isReadOnly()) { final DerivedAttribute derivedAttribute = e.getValue(); ldapAttributeTypes.addAll(derivedAttribute.getLDAPAttributeTypes()); } } SCIMAttribute meta = scimObject.getAttribute( SCIMConstants.SCHEMA_URI_CORE, "meta"); if (meta != null) { //The "attributes" sub-attribute is specifically for deleting attribute //values when performing a PATCH operation. if(meta.getValue().hasAttribute("attributes")) { Set scimAttributes = new LinkedHashSet(); SCIMAttribute attrToDelete = meta.getValue().getAttribute("attributes"); for(SCIMAttributeValue attr : attrToDelete.getValues()) { String rawAttributeName; if(attr.isComplex()) { rawAttributeName = attr.getSubAttributeValue("value", AttributeValueResolver.STRING_RESOLVER); } else { rawAttributeName = attr.getStringValue(); } AttributePath path = AttributePath.parse(rawAttributeName, getDefaultSchemaURI()); scimAttributes.add(path); } ldapAttributeTypes.addAll(toLDAPAttributeTypes(scimAttributes)); } } return ldapAttributeTypes; } /** * Map the replacement attributes in a SCIM object to LDAP modifications. * * @param currentEntry The current LDAP entry representing the SCIM object. * @param scimObject The object containing attributes to be mapped. * @param mappedAttributeNames The names of the modifiable attributes. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A list of LDAP modifications mapped from the SCIM object. This * should never be {@code null} but may be empty. * * @throws SCIMException If the modifications could not be mapped. */ public List toLDAPModificationsForPut( final Entry currentEntry, final SCIMObject scimObject, final String[] mappedAttributeNames, final LDAPRequestInterface ldapInterface) throws SCIMException { final List attributes = toLDAPAttributes(scimObject, ldapInterface); final Entry entry = new Entry(currentEntry.getDN(), attributes); return Entry.diff(currentEntry, entry, false, false, mappedAttributeNames); } /** * Map the replacement attributes in a SCIM object to LDAP modifications * according to the PATCH specification. * * @param currentEntry The current LDAP entry representing the SCIM object. * @param scimObject The object containing attributes to be mapped. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A list of LDAP modifications mapped from the SCIM object. This * should never be {@code null} but may be empty. * * @throws SCIMException If the modifications could not be mapped. */ public List toLDAPModificationsForPatch( final Entry currentEntry, final SCIMObject scimObject, final LDAPRequestInterface ldapInterface) throws SCIMException { SCIMAttribute meta = scimObject.getAttribute(SCIMConstants.SCHEMA_URI_CORE, CoreSchema.META_DESCRIPTOR.getName()); HashMap deletedAttrs = new HashMap(); LinkedList mods = new LinkedList(); if (meta != null) { SCIMAttributeValue value = meta.getValue(); SCIMAttribute attributesAttr = value.getAttribute("attributes"); if (attributesAttr != null) { Set scimAttributes = new LinkedHashSet(); for (SCIMAttributeValue val : attributesAttr.getValues()) { String rawAttributeName; if (val.isComplex()) { rawAttributeName = val.getSubAttributeValue("value", AttributeValueResolver.STRING_RESOLVER); } else { rawAttributeName = val.getStringValue(); } AttributePath path = AttributePath.parse(rawAttributeName, getDefaultSchemaURI()); scimAttributes.add(path); } Set ldapAttributes = toLDAPAttributeTypes(scimAttributes); if (Debug.debugEnabled()) { Debug.debug(Level.FINE, DebugType.OTHER, "LDAP attributes to remove are: " + ldapAttributes); } for (String attr : ldapAttributes) { deletedAttrs.put(attr.toLowerCase(), new Modification(ModificationType.DELETE, attr)); } } } Set schemas = scimObject.getSchemas(); for (String schema : schemas) { Collection attributes = scimObject.getAttributes(schema); for (SCIMAttribute attr : attributes) { // Skip the meta attribute. if (schema.equals(SCIMConstants.SCHEMA_URI_CORE) && attr.getName().equalsIgnoreCase( CoreSchema.META_DESCRIPTOR.getName())) { continue; } if(attr.getAttributeDescriptor().isMultiValued()) { //The attr is multi-valued, so merge it into the current value for (SCIMAttributeValue value : attr.getValues()) { if(value.isComplex()) { String operation = value.getSubAttributeValue( "operation", AttributeValueResolver.STRING_RESOLVER); if ("delete".equalsIgnoreCase(operation)) { //delete this value from the set of values for this attribute SCIMObject tempObject = new SCIMObject(); SCIMAttribute attrToDelete = SCIMAttribute.create(attr.getAttributeDescriptor(), value); tempObject.setAttribute(attrToDelete); for(Attribute attribute : toLDAPAttributes(tempObject, ldapInterface)) { String attrName = attribute.getName(); if(!deletedAttrs.containsKey(attrName.toLowerCase())) { // All values may be deleted already, in which case we // don't need to add another value specific delete mod. mods.add(new Modification(ModificationType.DELETE, attrName, attribute.getRawValues())); } } continue; } } //add this value to the set of values for this attribute SCIMObject tempObject = new SCIMObject(); SCIMAttribute attrToAdd = SCIMAttribute.create(attr.getAttributeDescriptor(), value); tempObject.setAttribute(attrToAdd); for(Attribute attribute : toLDAPAttributes(tempObject, ldapInterface)) { String attrName = attribute.getName(); if(deletedAttrs.remove(attrName.toLowerCase()) == null) { mods.add(new Modification(ModificationType.ADD, attrName, attribute.getRawValues())); } else { // Replace the delete/add with a single replace mod. mods.add(new Modification(ModificationType.REPLACE, attrName, attribute.getRawValues())); } } } } else { //The attr is single-valued, so just replace it on the newObject. SCIMObject tempObject = new SCIMObject(); tempObject.setAttribute(attr); for(Attribute attribute : toLDAPAttributes(tempObject, ldapInterface)) { String attrName = attribute.getName(); deletedAttrs.remove(attrName.toLowerCase()); mods.add(new Modification(ModificationType.REPLACE, attrName, attribute.getRawValues())); } } } } mods.addAll(0, deletedAttrs.values()); return mods; } /** * Map the provided SCIM filter to an LDAP filter. * * @param filter The SCIM filter to be mapped, or {@code null} if no filter * parameters were provided. * @param ldapInterface An optional LDAP interface that can be used to * map filters using derived attributes. * @return An LDAP filter or {@code null} if the SCIM filter could not be * mapped and will not match anything. * @throws SCIMException If an error occurs during the mapping. */ public Filter toLDAPFilter(final SCIMFilter filter, final LDAPRequestInterface ldapInterface) throws SCIMException { if (filter == null) { return searchResolver.getFilter(); } final Filter filterComponent = toLDAPFilterComponent(filter, ldapInterface); if (filterComponent == null) { return null; } else if(searchResolver.getFilter() != null) { return Filter.createANDFilter(filterComponent, searchResolver.getFilter()); } else { return filterComponent; } } /** * Get the search base DNs to be used for querying. * * @return The search base DN to be used for querying. */ public Set getSearchBaseDNs() { return searchResolver.getBaseDNs(); } /** * Determine whether the provided DN could be a resource entry that * satisfies the criteria for this ResourceMapper. * * @param dn The DN for which to make the determination. * * @return {@code true} if the LDAP entry satisfies the criteria for this * resolver. */ final boolean isDnInScope(final String dn) { return searchResolver.isDnInScope(dn); } /** * Map the provided SCIM sort parameters to an LDAP sort control. * * @param sortParameters The SCIM sort parameters to be mapped. * * @return An LDAP sort control. * @throws SCIMException If the sort parameters could not be mapped. */ public Control toLDAPSortControl(final SortParameters sortParameters) throws SCIMException { final AttributePath attributePath = sortParameters.getSortBy(); final AttributeDescriptor attributeDescriptor = resourceDescriptor.getAttribute(attributePath.getAttributeSchema(), attributePath.getAttributeName()); AttributeMapper attributeMapper = attributeMappers.get(attributeDescriptor); //TODO: handle if scimAttributeType == meta here if (attributeMapper == null) { throw new InvalidResourceException("Cannot sort by attribute " + sortParameters.getSortBy()); } final ServerSideSortRequestControl c = attributeMapper.toLDAPSortControl(sortParameters); if (c == null) { throw new InvalidResourceException("Cannot sort by attribute " + sortParameters.getSortBy()); } return new ServerSideSortRequestControl(true, c.getSortKeys()); } /** * Map the attributes in an LDAP entry to SCIM attributes. * * @param entry The LDAP entry containing attributes to be * mapped. * @param queryAttributes The set of SCIM attributes that are requested * to be returned. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A list of SCIM attributes mapped from the LDAP entry. This should * never be {@code null} but may be empty. * @throws SCIMException If the attributes could not be mapped. */ public List toSCIMAttributes( final Entry entry, final SCIMQueryAttributes queryAttributes, final LDAPRequestInterface ldapInterface) throws SCIMException { return toSCIMAttributes(new SearchResultEntry(entry), queryAttributes, ldapInterface); } /** * Map the attributes in an LDAP search result entry to SCIM attributes. * * @param entry The LDAP entry containing attributes to be * mapped. * @param queryAttributes The set of SCIM attributes that are requested * to be returned. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A list of SCIM attributes mapped from the LDAP entry. This should * never be {@code null} but may be empty. * @throws SCIMException If the attributes could not be mapped. */ public List toSCIMAttributes( final SearchResultEntry entry, final SCIMQueryAttributes queryAttributes, final LDAPRequestInterface ldapInterface) throws SCIMException { final List attributes = new ArrayList(); //Keep a list of the derived attributes that we add to the result set final Set derivedAttrs = new HashSet(derivedAttributes.size()); if (ldapInterface != null) { for (final Map.Entry e : derivedAttributes.entrySet()) { if (queryAttributes.isAttributeRequested(e.getKey())) { derivedAttrs.add(e.getKey()); final DerivedAttribute derivedAttribute = e.getValue(); final SCIMAttribute attribute = derivedAttribute.searchEntryToSCIMAttribute( entry, ldapInterface, searchResolver); if (attribute != null) { final SCIMAttribute paredAttribute = queryAttributes.pareAttribute(attribute); if (paredAttribute != null) { attributes.add(paredAttribute); } } } } } for (final AttributeMapper attributeMapper : attributeMappers.values()) { if(derivedAttrs.contains(attributeMapper.getAttributeDescriptor())) { //If this attribute has a derivation, then it was already added above. continue; } if (queryAttributes.isAttributeRequested( attributeMapper.getAttributeDescriptor())) { final SCIMAttribute attribute = attributeMapper.toSCIMAttribute(entry); if (attribute != null) { final SCIMAttribute paredAttribute = queryAttributes.pareAttribute(attribute); if (paredAttribute != null) { attributes.add(paredAttribute); } } } } return attributes; } /** * Map an LDAP entry to a SCIM resource. * * @param entry The LDAP entry containing attributes to be * mapped. * @param queryAttributes The set of SCIM attributes that are requested * to be returned. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A SCIM object mapped from the LDAP entry, or {@code null} if this * entry cannot be mapped to a SCIM object. * @throws SCIMException If the entry could not be mapped. */ public SCIMObject toSCIMObject(final Entry entry, final SCIMQueryAttributes queryAttributes, final LDAPRequestInterface ldapInterface) throws SCIMException { return toSCIMObject(new SearchResultEntry(entry), queryAttributes, ldapInterface); } /** * Map an LDAP search result entry to a SCIM resource. * * @param entry The LDAP entry containing attributes to be * mapped, and optional controls as input to the * mapping. * @param queryAttributes The set of SCIM attributes that are requested * to be returned. * @param ldapInterface An optional LDAP interface that can be used to * derive attributes from other entries. * * @return A SCIM object mapped from the LDAP entry, or {@code null} if this * entry cannot be mapped to a SCIM object. * @throws SCIMException If the entry could not be mapped. */ public SCIMObject toSCIMObject( final SearchResultEntry entry, final SCIMQueryAttributes queryAttributes, final LDAPRequestInterface ldapInterface) throws SCIMException { if (searchResolver.getFilter() != null) { try { if (!searchResolver.getFilter().matchesEntry(entry)) { return null; } } catch (LDAPException e) { Debug.debugException(e); throw new RuntimeException(e.getExceptionMessage()); } } final List attributes = toSCIMAttributes(entry, queryAttributes, ldapInterface); final SCIMObject scimObject = new SCIMObject(); for (final SCIMAttribute a : attributes) { Validator.ensureTrue(scimObject.addAttribute(a)); } return scimObject; } /** * Create a resource mapper from the name of a class that extends the * {@code ResourceMapper} abstract class. * * @param className The name of a class that extends {@code ResourceMapper}. * * @return A new instance of the ResourceMapper class. */ public static ResourceMapper create(final String className) { if (className == null) { return new ResourceMapper(); } Class clazz; try { clazz = Class.forName(className, true, ResourceMapper.class.getClassLoader()); } catch (ClassNotFoundException e) { Debug.debugException(e); throw new IllegalArgumentException( "Class '" + className + "' not found", e); } final Object object; try { object = clazz.newInstance(); } catch (Exception e) { Debug.debugException(e); throw new IllegalArgumentException( "Cannot create instance of class '" + className + "'", e); } if (!(object instanceof ResourceMapper)) { throw new IllegalArgumentException( "Class '" + className + "' is not a ResourceMapper"); } return (ResourceMapper)object; } /** * Map a SCIM filter component to an LDAP filter component. * * @param filter The SCIM filter component to be mapped. * @param ldapInterface An optional LDAP interface that can be used to * map filters using derive attributes. * @return The LDAP filter component, or {@code null} if the filter * component could not be mapped and will not match anything. * @throws SCIMException If an error occurs during the mapping. */ protected Filter toLDAPFilterComponent(final SCIMFilter filter, final LDAPRequestInterface ldapInterface) throws SCIMException { final SCIMFilterType filterType = filter.getFilterType(); switch (filterType) { case AND: final List andFilterComponents = new ArrayList(); for (SCIMFilter f : filter.getFilterComponents()) { final Filter filterComponent = toLDAPFilterComponent(f, ldapInterface); if (filterComponent != null) { andFilterComponents.add(filterComponent); } else { // AND nothing is still nothing return null; } } return Filter.createANDFilter(andFilterComponents); case OR: final List orFilterComponents = new ArrayList(); for (SCIMFilter f : filter.getFilterComponents()) { final Filter filterComponent = toLDAPFilterComponent(f, ldapInterface); if (filterComponent != null) { orFilterComponents.add(filterComponent); } } return Filter.createORFilter(orFilterComponents); default: final AttributePath filterAttribute = filter.getFilterAttribute(); final AttributeDescriptor attributeDescriptor = resourceDescriptor.getAttribute( filterAttribute.getAttributeSchema(), filterAttribute.getAttributeName()); AttributeMapper attributeMapper; if (attributeDescriptor.equals( metaAttributeMapper.getAttributeDescriptor())) { attributeMapper = metaAttributeMapper; } else if (idAttributeMapper != null && attributeDescriptor.equals( idAttributeMapper.getAttributeDescriptor())) { attributeMapper = idAttributeMapper; } else { attributeMapper = attributeMappers.get(attributeDescriptor); } DerivedAttribute derivedAttribute = derivedAttributes.get(attributeDescriptor); final List filters = new ArrayList(2); if (attributeMapper != null) { filters.add(attributeMapper.toLDAPFilter(filter)); } if(derivedAttribute != null && ldapInterface != null) { filters.add(derivedAttribute.toLDAPFilter(filter, ldapInterface, searchResolver)); } if (filters.size() == 2) { return Filter.createORFilter(filters); } if (!filters.isEmpty()) { return filters.get(0); } return null; } } /** * Gets an AttributeMapper for the SCIM Meta object (part of the core schema). * * @return an AttributeMapper */ private AttributeMapper createMetaAttributeMapper() { List transformations = new ArrayList(); final Transformation dateTransformation = Transformation.create(GeneralizedTimeTransformation.class.getName(), null); transformations.add(new SubAttributeTransformation("created", new AttributeTransformation("createTimestamp", dateTransformation))); transformations.add(new SubAttributeTransformation("lastModified", new AttributeTransformation("modifyTimestamp", dateTransformation))); return new ComplexSingularAttributeMapper( CoreSchema.META_DESCRIPTOR, transformations); } /** * Determines whether the SCIM resource ID maps to the LDAP DN. * * @return {@code true} if the SCIM resource ID maps to the LDAP DN or * {@code false} if the ID maps to some other attribute. */ public boolean idMapsToDn() { return searchResolver.idMapsToDn(); } /** * Returns the LDAP attribute that the SCIM resource ID maps to, or * {@code null} if the SCIM ID maps to the LDAP DN. * * @return The LDAP attribute that the SCIM resource ID maps to, or * {@code null} if the SCIM ID maps to the LDAP DN. */ public String getIdAttribute() { return searchResolver.getIdAttribute(); } /** * Retrieve a resource ID from an LDAP entry. * * @param entry The LDAP entry, which must contain a value for the * resource ID attribute unless the resource ID maps to the * LDAP DN. * * @return The resource ID of the entry. * * @throws SCIMException If the resource ID could not be determined. */ public String getIdFromEntry(final Entry entry) throws SCIMException { return searchResolver.getIdFromEntry(entry); } /** * Construct the the entry DN from the entry attributes based on the * LDAP Add parameters. * * @param entry The LDAP entry to construct the DN from. * * @return The constructed DN for the entry or {@code null} if the LDAP * ADD parameters are not defined. * * @throws SCIMException If the resource ID could not be determined. */ public String constructEntryDN(final Entry entry) throws SCIMException { if(dnConstructor != null) { try { return dnConstructor.constructValue(entry); } catch (Exception e) { throw new InvalidResourceException("An error occurred while " + "constructing the DN for a mapped entry: " + e.getLocalizedMessage(), e); } } throw new InvalidResourceException("A DNTemplate must be defined in the " + "LDAPAdd section of the resource mapping configuration to map User " + "resources to LDAP entry DNs."); } /** * Read the LDAP entry identified by the given resource ID. No attributes * are returned from the entry. * * @param ldapInterface The LDAP interface to use to read the entry. * @param resourceID The requested SCIM resource ID. * * @return The LDAP entry for the given resource ID. * * @throws SCIMException If the entry could not be read. */ public SearchResultEntry getEntryWithoutAttrs( final LDAPRequestInterface ldapInterface, final String resourceID) throws SCIMException { return getEntry(ldapInterface, resourceID, "1.1"); } /** * Read the LDAP entry identified by the given resource ID. * * @param ldapInterface The LDAP interface to use to read the entry. * @param resourceID The requested SCIM resource ID. * @param attributes The requested LDAP attributes. * * @return The LDAP entry for the given resource ID. * * @throws SCIMException If the entry could not be read. */ public SearchResultEntry getEntry(final LDAPRequestInterface ldapInterface, final String resourceID, final String... attributes) throws SCIMException { final List controls = new ArrayList(); return searchResolver.getEntry(ldapInterface, resourceID, controls, attributes); } /** * Read the LDAP entry identified by the given resource ID. The LDAP entry * should be in a form suitable for mapping to a SCIM entry that will be * returned to the client. * * @param ldapInterface The LDAP interface to use to read the entry. * @param resourceID The requested SCIM resource ID. * @param queryAttributes The set of requested SCIM attributes. * @param attributes The requested LDAP attributes. * * @return The LDAP entry for the given resource ID. * * @throws SCIMException If the entry could not be read. */ public SearchResultEntry getReturnEntry( final LDAPRequestInterface ldapInterface, final String resourceID, final SCIMQueryAttributes queryAttributes, final String... attributes) throws SCIMException { // Include any controls that are needed by derived attributes. final List controls = new ArrayList(); addSearchControls(controls, queryAttributes); return searchResolver.getEntry(ldapInterface, resourceID, controls, attributes); } /** * Add any search controls that are needed by derived attributes when the * LDAP entry is fetched. * * @param controls The list of controls that will be used to fetch * the LDAP entry. * @param queryAttributes The set of requested SCIM attributes. */ public void addSearchControls(final List controls, final SCIMQueryAttributes queryAttributes) { for (final Map.Entry e : derivedAttributes.entrySet()) { if (queryAttributes.isAttributeRequested(e.getKey())) { final DerivedAttribute derivedAttribute = e.getValue(); derivedAttribute.addSearchControls(controls); } } } /** * Returns the LDAP attribute that the SCIM password attribute maps to, * or null if there is no mapping for the password attribute. * * @return The LDAP attribute name, or null if there is no * mapping for the password attribute. */ public String getPasswordAttribute() { if(passwordAttributeMapper != null) { Iterator iter = passwordAttributeMapper .getLDAPAttributeTypes().iterator(); if(iter.hasNext()) { return iter.next(); } } return null; } /** * Translate an LDAP exception to a SCIM exception. * * @param e The LDAP exception to be translated. * * @return The SCIM exception. */ public static SCIMException toSCIMException(final LDAPException e) { return toSCIMException( com.unboundid.util.StaticUtils.getExceptionMessage(e), e); } /** * Translate an LDAP exception to a SCIM exception. * * @param errorMessage The error message to use in the SCIM exception. * @param e The LDAP exception to be translated. * * @return The SCIM exception. */ public static SCIMException toSCIMException(final String errorMessage, final LDAPException e) { switch (e.getResultCode().intValue()) { case ResultCode.NO_SUCH_ATTRIBUTE_INT_VALUE: case ResultCode.INVALID_ATTRIBUTE_SYNTAX_INT_VALUE: case ResultCode.INVALID_DN_SYNTAX_INT_VALUE: case ResultCode.UNWILLING_TO_PERFORM_INT_VALUE: case ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE: case ResultCode.NOT_ALLOWED_ON_NONLEAF_INT_VALUE: case ResultCode.NOT_ALLOWED_ON_RDN_INT_VALUE: case ResultCode.OBJECT_CLASS_MODS_PROHIBITED_INT_VALUE: return new InvalidResourceException(errorMessage, e); case ResultCode.INVALID_CREDENTIALS_INT_VALUE: return new UnauthorizedException(errorMessage, e); case ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE: return new ForbiddenException(errorMessage, e); case ResultCode.NO_SUCH_OBJECT_INT_VALUE: return new ResourceNotFoundException(errorMessage, e); case ResultCode.CONSTRAINT_VIOLATION_INT_VALUE: case ResultCode.ATTRIBUTE_OR_VALUE_EXISTS_INT_VALUE: case ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE: return new ResourceConflictException(errorMessage, e); case ResultCode.ASSERTION_FAILED_INT_VALUE: return new PreconditionFailedException(errorMessage, e); default: return new ServerErrorException(errorMessage, e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy