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

com.unboundid.scim.ldap.ComplexSingularAttributeMapper 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.asn1.ASN1OctetString;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
import com.unboundid.ldap.sdk.controls.SortKey;
import com.unboundid.scim.schema.AttributeDescriptor;
import com.unboundid.scim.sdk.AttributePath;
import com.unboundid.scim.sdk.InvalidResourceException;
import com.unboundid.scim.sdk.SCIMAttribute;
import com.unboundid.scim.sdk.SCIMAttributeValue;
import com.unboundid.scim.sdk.SCIMObject;
import com.unboundid.scim.sdk.SCIMFilter;
import com.unboundid.scim.sdk.SCIMFilterType;
import com.unboundid.scim.sdk.SortParameters;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.unboundid.scim.sdk.StaticUtils.toLowerCase;



/**
 * This class provides an attribute mapper that maps a singular complex SCIM
 * attribute to several single-valued LDAP attributes, where each LDAP
 * attribute holds one of the SCIM sub-attributes.
 */
public class ComplexSingularAttributeMapper extends AttributeMapper
{
  /**
   * The set of sub-attribute transformations indexed by the name of the
   * sub-attribute.
   */
  private final Map map;

  /**
   * The set of LDAP attributes that are mapped by this attribute mapper.
   */
  private final Set ldapAttributeTypes;



  /**
   * Create a new instance of a complex singular attribute mapper.
   *
   * @param attributeDescriptor  The SCIM attribute type that is mapped by this
   *                             attribute mapper.
   * @param transformations    The set of sub-attribute transformations for
   *                           this attribute mapper.
   */
  public ComplexSingularAttributeMapper(
      final AttributeDescriptor attributeDescriptor,
      final List transformations)
  {
    super(attributeDescriptor);

    map = new HashMap();
    ldapAttributeTypes = new HashSet();
    for (final SubAttributeTransformation t : transformations)
    {
      map.put(toLowerCase(t.getSubAttribute()), t);
      ldapAttributeTypes.add(t.getAttributeTransformation().getLdapAttribute());
    }
  }



  @Override
  public Set getLDAPAttributeTypes()
  {
    return ldapAttributeTypes;
  }



  @Override
  public Filter toLDAPFilter(final SCIMFilter filter)
      throws InvalidResourceException
  {
    final SCIMFilterType type = filter.getFilterType();

    String ldapAttributeType = null;
    String ldapFilterValue = null;

    if(type != SCIMFilterType.AND && type != SCIMFilterType.OR)
    {
      final String subAttributeName =
             filter.getFilterAttribute().getSubAttributeName();
      if(subAttributeName == null)
      {
        throw new InvalidResourceException(filter.getFilterAttribute() +
            " must be a path to a sub-attribute");
      }

      final SubAttributeTransformation subAttributeTransformation =
          map.get(toLowerCase(subAttributeName));
      if(subAttributeTransformation == null)
      {
       // Make sure the sub-attribute is defined.
        getAttributeDescriptor().getSubAttribute(subAttributeName);
        return null; //match nothing
      }

      final AttributeTransformation attributeTransformation =
                subAttributeTransformation.getAttributeTransformation();

      ldapAttributeType = attributeTransformation.getLdapAttribute();

      if(filter.getFilterValue() != null)
      {
        final Transformation t = attributeTransformation.getTransformation();
        ldapFilterValue = t.toLDAPFilterValue(filter.getFilterValue());
      }
    }
    else
    {
      // We don't have to worry about AND and OR filter types since they are
      // handled earlier by the resource mapper.
      throw new RuntimeException("Invalid filter type: " + type);
    }

    switch(type)
    {
      case EQUALITY:
        return Filter.createEqualityFilter(ldapAttributeType, ldapFilterValue);
      case CONTAINS:
        return Filter.createSubstringFilter(ldapAttributeType, null,
                                    new String[] { ldapFilterValue }, null);
      case PRESENCE:
        return Filter.createPresenceFilter(ldapAttributeType);
      case STARTS_WITH:
        return Filter.createSubstringFilter(ldapAttributeType, ldapFilterValue,
                                              null, null);
      case GREATER_THAN:
        return Filter.createANDFilter(
          Filter.createGreaterOrEqualFilter(ldapAttributeType, ldapFilterValue),
          Filter.createNOTFilter(
              Filter.createEqualityFilter(ldapAttributeType, ldapFilterValue)));
      case GREATER_OR_EQUAL:
        return Filter.createGreaterOrEqualFilter(ldapAttributeType,
                ldapFilterValue);
      case LESS_THAN:
        return Filter.createANDFilter(
          Filter.createLessOrEqualFilter(ldapAttributeType, ldapFilterValue),
          Filter.createNOTFilter(
              Filter.createEqualityFilter(ldapAttributeType, ldapFilterValue)));
      case LESS_OR_EQUAL:
        return Filter.createLessOrEqualFilter(ldapAttributeType,
                ldapFilterValue);
      default:
        throw new RuntimeException(
                "Filter type " + type + " is not supported");
    }
  }



  @Override
  public Set toLDAPAttributeTypes(final AttributePath scimAttribute)
      throws InvalidResourceException
  {
    final String subAttributeName = scimAttribute.getSubAttributeName();
    if(subAttributeName == null)
    {
      throw new InvalidResourceException(scimAttribute.getAttributeName() +
          " must be a path to a sub-attribute");
    }

    final SubAttributeTransformation subAttributeTransformation =
        map.get(toLowerCase(subAttributeName));
    if(subAttributeTransformation == null)
    {
      // Make sure the sub-attribute is defined.
      getAttributeDescriptor().getSubAttribute(subAttributeName);
      return null; //match nothing
    }

    final AttributeTransformation attributeTransformation =
        subAttributeTransformation.getAttributeTransformation();

    final String ldapAttributeType = attributeTransformation.getLdapAttribute();
    return Collections.singleton(ldapAttributeType);
  }



  @Override
  public ServerSideSortRequestControl toLDAPSortControl(
      final SortParameters sortParameters)
      throws InvalidResourceException
  {
    final String subAttributeName =
        sortParameters.getSortBy().getSubAttributeName();
    if(subAttributeName == null)
    {
      throw new InvalidResourceException("Cannot sort by attribute because " +
          sortParameters.getSortBy() + " must be a path to a sub-attribute");
    }

    final SubAttributeTransformation subAttributeTransformation =
        map.get(toLowerCase(subAttributeName));
    if(subAttributeTransformation == null)
    {
      // Make sure the sub-attribute is defined.
      getAttributeDescriptor().getSubAttribute(subAttributeName);
      throw new InvalidResourceException("Cannot sort by attribute " +
          sortParameters.getSortBy() + " because it has no mapping");
    }

    final AttributeTransformation attributeTransformation =
        subAttributeTransformation.getAttributeTransformation();
    if(attributeTransformation.getTransformation()
        instanceof DefaultTransformation)
    {
      final AttributeDescriptor subAttributeDescriptor =
          getAttributeDescriptor().getSubAttribute(subAttributeName);
      final boolean reverseOrder = !sortParameters.isAscendingOrder();
      if(subAttributeDescriptor.getDataType() ==
          AttributeDescriptor.DataType.STRING)
      {
        return new ServerSideSortRequestControl(
            new SortKey(attributeTransformation.getLdapAttribute(),
                subAttributeDescriptor.isCaseExact() ?
                    CASE_EXACT_OMR_OID : CASE_IGNORE_OMR_OID, reverseOrder));
      }
      return new ServerSideSortRequestControl(
          new SortKey(attributeTransformation.getLdapAttribute(),
              reverseOrder));
    }
    else
    {
      throw new InvalidResourceException("Cannot sort by attribute " +
          sortParameters.getSortBy() + " because it is mapped with custom " +
          "transformations");
    }
  }



  @Override
  public void toLDAPAttributes(final SCIMObject scimObject,
                               final Collection attributes)
      throws InvalidResourceException {
    final SCIMAttribute scimAttribute =
        scimObject.getAttribute(getAttributeDescriptor().getSchema(),
                                getAttributeDescriptor().getName());
    if (scimAttribute != null)
    {
      final SCIMAttributeValue value = scimAttribute.getValue();

      for (final SubAttributeTransformation sat : map.values())
      {
        final AttributeTransformation at = sat.getAttributeTransformation();
        final String scimType = sat.getSubAttribute();
        final String ldapType = at.getLdapAttribute();

        final SCIMAttribute subAttribute = value.getAttribute(scimType);
        if (subAttribute != null)
        {
          final AttributeDescriptor subDescriptor =
              getAttributeDescriptor().getSubAttribute(scimType);
          final ASN1OctetString v = at.getTransformation().toLDAPValue(
              subDescriptor, subAttribute.getValue());
          attributes.add(new Attribute(ldapType, v));
        }
      }
    }
  }



  @Override
  public SCIMAttribute toSCIMAttribute(final Entry entry)
      throws InvalidResourceException {
    final List subAttributes = new ArrayList();

    for (final SubAttributeTransformation sat : map.values())
    {
      final String subAttributeName = sat.getSubAttribute();
      final AttributeTransformation at = sat.getAttributeTransformation();

      final AttributeDescriptor subDescriptor =
          getAttributeDescriptor().getSubAttribute(subAttributeName);
      final Attribute a = entry.getAttribute(at.getLdapAttribute());
      if (a != null)
      {
        final ASN1OctetString[] rawValues = a.getRawValues();
        if (rawValues.length > 0)
        {
          final SCIMAttributeValue value =
              at.getTransformation().toSCIMValue(subDescriptor, rawValues[0]);
          subAttributes.add(
              SCIMAttribute.create(subDescriptor, value));
        }
      }
    }

    if (subAttributes.isEmpty())
    {
      return null;
    }

    final SCIMAttributeValue complexValue =
        SCIMAttributeValue.createComplexValue(subAttributes);
    return SCIMAttribute.create(getAttributeDescriptor(),
        complexValue);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy