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

se.idsec.signservice.integration.dss.DssUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2019-2023 IDsec Solutions AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.idsec.signservice.integration.dss;

import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils;
import se.idsec.signservice.integration.authentication.SignerIdentityAttribute;
import se.idsec.signservice.integration.authentication.SignerIdentityAttributeValue;
import se.idsec.signservice.integration.certificate.CertificateAttributeMapping;
import se.idsec.signservice.integration.certificate.SigningCertificateRequirements;
import se.idsec.signservice.integration.core.error.impl.SignServiceProtocolException;
import se.swedenconnect.schemas.csig.dssext_1_1.CertRequestProperties;
import se.swedenconnect.schemas.csig.dssext_1_1.MappedAttributeType;
import se.swedenconnect.schemas.csig.dssext_1_1.PreferredSAMLAttributeNameType;
import se.swedenconnect.schemas.csig.dssext_1_1.RequestedCertAttributes;
import se.swedenconnect.schemas.saml_2_0.assertion.Assertion;
import se.swedenconnect.schemas.saml_2_0.assertion.Attribute;
import se.swedenconnect.schemas.saml_2_0.assertion.AttributeStatement;
import se.swedenconnect.schemas.saml_2_0.assertion.NameIDType;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Utilities for creating DSS elements.
 *
 * @author Martin Lindström ([email protected])
 * @author Stefan Santesson ([email protected])
 */
public class DssUtils {

  /** The DSS profile we use. */
  public static final String DSS_PROFILE = "http://id.elegnamnden.se/csig/1.1/dss-ext/profile";

  /** The namespace for DSS extension. */
  public static final String DSS_EXT_NAMESPACE = "http://id.elegnamnden.se/csig/1.1/dss-ext/ns";

  /**
   * Creates a NameID object.
   *
   * @param name the name
   * @return the NameID object
   */
  public static NameIDType toEntity(final String name) {
    final NameIDType entity = new NameIDType();
    entity.setValue(name);
    entity.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
    return entity;
  }

  /**
   * Given an assertion the {@code AttributeStatement} is extracted.
   *
   * @param assertion the assertion
   * @return an AttributeStatement
   */
  public static AttributeStatement getAttributeStatement(final Assertion assertion) {
    return assertion.getStatementsAndAuthnStatementsAndAuthzDecisionStatements().stream()
        .filter(AttributeStatement.class::isInstance)
        .map(AttributeStatement.class::cast)
        .findFirst()
        .orElse(null);
  }

  /**
   * Gets a String-attribute value from the given statement.
   *
   * @param statement the statement
   * @param name the attribute name
   * @return the value or null if no value is found
   */
  public static String getAttributeValue(final AttributeStatement statement, final String name) {
    return getAttributeValue(statement, name, String.class);
  }

  /**
   * Gets an attribute value from the given statement having the given type.
   *
   * @param statement the statement
   * @param name the attribute name
   * @param type the type of the attribute value
   * @return the value or null if no value is found
   */
  public static  T getAttributeValue(final AttributeStatement statement, final String name, final Class type) {
    return statement.getAttributesAndEncryptedAttributes().stream()
        .filter(Attribute.class::isInstance)
        .map(Attribute.class::cast)
        .filter(a -> Objects.equals(a.getName(), name))
        .filter(Attribute::isSetAttributeValues)
        .map(a -> a.getAttributeValues().get(0))
        .filter(type::isInstance)
        .map(type::cast)
        .findFirst()
        .orElse(null);
  }

  /**
   * Converts a list of {@link SignerIdentityAttributeValue} objects into a {@code AttributeStatement} element.
   *
   * @param attributes list of attributes
   * @return an AttributeStatement element
   * @throws SignServiceProtocolException for encoding/decoding errors
   */
  public static AttributeStatement toAttributeStatement(@Nonnull final List attributes)
      throws SignServiceProtocolException {

    final AttributeStatement attributeStatement = new AttributeStatement();
    for (final SignerIdentityAttributeValue siav : attributes) {

      final Attribute attribute = toAttribute(siav);

      // We want to handle multivalued attributes in both directions ...
      final Attribute existing = attributeStatement.getAttributesAndEncryptedAttributes().stream()
          .filter(Attribute.class::isInstance)
          .map(Attribute.class::cast)
          .filter(a -> Objects.equals(a.getName(), siav.getName()))
          .findFirst()
          .orElse(null);

      if (existing != null) {
        existing.getAttributeValues().add(attribute.getAttributeValues().get(0));
      }
      else {
        attributeStatement.getAttributesAndEncryptedAttributes().add(attribute);
      }
    }

    return attributeStatement;
  }

  /**
   * Converts from an {@code AttributeStatement} object to a list of {@code SignerIdentityAttributeValue} objects.
   *
   * @param attributeStatement the statement to convert
   * @return a list of SignerIdentityAttributeValue objects
   */
  public static List fromAttributeStatement(
      @Nonnull final AttributeStatement attributeStatement) {

    final List list = new ArrayList<>();

    attributeStatement.getAttributesAndEncryptedAttributes().stream()
        .filter(Attribute.class::isInstance)
        .map(Attribute.class::cast)
        .map(DssUtils::toSignerIdentityAttributeValue)
        .forEach(list::addAll);

    return list;
  }

  /**
   * Converts a {@link SigningCertificateRequirements} object into a {@code CertRequestProperties} element.
   *
   * @param certReqs signing certificate requirements
   * @param authnContextClassRefs the level of assurance(s)
   * @return a CertRequestProperties elements
   */
  public static CertRequestProperties toCertRequestProperties(final SigningCertificateRequirements certReqs,
      final List authnContextClassRefs) {

    final CertRequestProperties crp =
        (new se.swedenconnect.schemas.csig.dssext_1_1.ObjectFactory()).createCertRequestProperties();
    crp.setCertType(certReqs.getCertificateType().getType());
    crp.getAuthnContextClassRefs().addAll(authnContextClassRefs);

    if (certReqs.getAttributeMappings() != null) {
      final RequestedCertAttributes certAttributes = new RequestedCertAttributes();
      for (final CertificateAttributeMapping mapping : certReqs.getAttributeMappings()) {
        final MappedAttributeType certAttr = new MappedAttributeType();
        certAttr.setCertAttributeRef(mapping.getDestination().getName());
        certAttr.setCertNameType(mapping.getDestination().getType());
        if (StringUtils.isNotBlank(mapping.getDestination().getFriendlyName())) {
          certAttr.setFriendlyName(mapping.getDestination().getFriendlyName());
        }
        if (StringUtils.isNotBlank(mapping.getDestination().getDefaultValue())) {
          certAttr.setDefaultValue(mapping.getDestination().getDefaultValue());
        }
        certAttr.setRequired(
            mapping.getDestination().getRequired() != null && mapping.getDestination().getRequired());

        if (mapping.getSources() != null) {
          int order = 0;
          for (final SignerIdentityAttribute sia : mapping.getSources()) {
            final PreferredSAMLAttributeNameType samlAttribute = new PreferredSAMLAttributeNameType();
            if (mapping.getSources().size() > 1) {
              samlAttribute.setOrder(order++);
            }
            samlAttribute.setValue(sia.getName());
            certAttr.getSamlAttributeNames().add(samlAttribute);
          }
        }
        certAttributes.getRequestedCertAttributes().add(certAttr);
      }
      crp.setRequestedCertAttributes(certAttributes);
    }

    return crp;
  }

  /**
   * Creates a SAML {@link Attribute} given a {@link SignerIdentityAttributeValue}.
   *
   * @param value the value to transform into an Attribute
   * @return an Attribute
   * @throws SignServiceProtocolException for protocol errors
   */
  public static Attribute toAttribute(final SignerIdentityAttributeValue value) throws SignServiceProtocolException {
    if (value.getType() != null && !SignerIdentityAttribute.SAML_TYPE.equalsIgnoreCase(value.getType())) {
      throw new SignServiceProtocolException(
          String.format("Unsupported attribute type '%s' - Only '%s' is supported",
              value.getType(), SignerIdentityAttribute.SAML_TYPE));
    }
    final Attribute attribute = new Attribute();
    attribute.setName(value.getName());
    attribute.setNameFormat(value.getNameFormat());
    attribute.getAttributeValues().add(toAttributeValue(value));
    return attribute;
  }

  /**
   * Given a {@link SignerIdentityAttributeValue} the method extracts its value and converts it to the correct type.
   *
   * @param siav the object to convert
   * @return the attribute value
   * @throws SignServiceProtocolException for non supported values
   */
  public static Object toAttributeValue(final SignerIdentityAttributeValue siav) throws SignServiceProtocolException {
    try {
      if (siav.getAttributeValueType() == null
          || SignerIdentityAttributeValue.DEFAULT_ATTRIBUTE_VALUE_TYPE.equals(siav.getAttributeValueType())) {
        return siav.getValue();
      }
      else if ("integer".equals(siav.getAttributeValueType())) {
        return new BigInteger(siav.getValue());
      }
      else if ("boolean".equals(siav.getAttributeValueType())) {
        if ("1".equals(siav.getValue())) {
          return Boolean.TRUE;
        }
        else if ("0".equals(siav.getAttributeValueType())) {
          return Boolean.FALSE;
        }
        else {
          return Boolean.parseBoolean(siav.getValue());
        }
      }
      else if ("dateTime".equalsIgnoreCase(siav.getAttributeValueType())
          || "date".equalsIgnoreCase(siav.getAttributeValueType())) {
        return DatatypeFactory.newInstance().newXMLGregorianCalendar(siav.getValue());
      }
      else {
        throw new SignServiceProtocolException(String.format("Attribute '%s' has type '%s' - Not supported",
            siav.getName(), siav.getAttributeValueType()));
      }
    }
    catch (final IllegalArgumentException | DatatypeConfigurationException e) {
      throw new SignServiceProtocolException(String.format("Attribute '%s' has type '%s' - could not parse value",
          siav.getName(), siav.getAttributeValueType()), e);
    }
  }

  /**
   * Given an attribute, the method transforms it into a {@link SignerIdentityAttributeValue}.
   * 

* Note: If the attribute is multi-valued, several {@link SignerIdentityAttributeValue} instances will be created. *

* * @param attribute the attribute to convert * @return a list of SignerIdentityAttributeValue objects */ public static List toSignerIdentityAttributeValue(final Attribute attribute) { final List result = new ArrayList<>(); for (final Object v : attribute.getAttributeValues()) { final SignerIdentityAttributeValue siav = new SignerIdentityAttributeValue(); siav.setType(SignerIdentityAttribute.SAML_TYPE); siav.setName(attribute.getName()); siav.setNameFormat(attribute.getNameFormat()); if (v instanceof final String s) { siav.setAttributeValueType("string"); siav.setValue(s); } else if (v instanceof final Boolean b) { siav.setAttributeValueType("boolean"); siav.setValue(b.toString()); } else if (v instanceof final BigInteger bigInteger) { siav.setAttributeValueType("integer"); siav.setValue(bigInteger.toString()); } else if (v instanceof final XMLGregorianCalendar t) { siav.setAttributeValueType(t.getXMLSchemaType().getLocalPart()); siav.setValue(t.toXMLFormat()); } else { // Hmm ... siav.setValue(v.toString()); } result.add(siav); } return result; } private DssUtils() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy