package com.airlock.iam.saml2.application.configuration;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.license.PluginLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringListProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import com.airlock.iam.saml2.infrastructure.plugin.SamlEncryptionProvider;
import com.airlock.iam.saml2.infrastructure.plugin.SamlSignatureProvider;
import com.google.common.collect.Maps;
import com.google.common.collect.ImmutableMap.Builder;
import com.sun.identity.saml.xmlsig.KeyProvider;
import com.sun.identity.saml2.common.SignatureAlgorithm;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;

@Plugin(description = "Federation settings used for all SAML 2.0 use-cases.", displayName = "SAML Federation Config")
@PluginLicenseRestriction(moduleAffiliation = {"SamlIdp", "SamlSp"})
@Groups(groupSequence = {"Basic Settings", "Signature Settings", "Plugin Settings"}, openGroups = {"Basic Settings", "Signature Settings"})
public final class SamlFederationConfig {
   static final String SIGNATURE_SETTINGS = "Signature Settings";
   static final String PLUGIN_SETTINGS = "Plugin Settings";
   private static final ELogger LOG = ELoggerFactory.getLogger(SamlFederationConfig.class);
   private static final String SHA1_AUTOMATIC_RSA_DSA = "SHA1 (automatic RSA/DSA)";
   private static Map<String, String> staticConfiguration = new Builder()
      .put("com.sun.identity.common.serverMode", "true")
      .put("com.sun.identity.saml.checkcert", "on")
      .put("com.sun.identity.saml2.xmlsig.SignatureProvider", SamlSignatureProvider.class.getName())
      .put("com.sun.identity.saml2.xmlenc.EncryptionProvider", SamlEncryptionProvider.class.getName())
      .put("com.iplanet.am.util.xml.validating", "off")
      .put("com.iplanet.services.debug.level", LOG.isDebugEnabled() ? "message" : "warning")
      .build();
   private final Map<String, SamlFederationConfig.FederationProperty> propertyMapper = Maps.newHashMap();
   @StringProperty(
      displayName = "Error Page URL",
      description = "URL where the user is redirected to when an internal SAML2 error happens. Use\n<ul>\n\t<li><tt>ui/app/error/message</tt> for Flow-based SAML2\n\t\t<br>Relative URIs not starting with a slash are resolved against the current context path.\n\t</li>\n</ul>\n<p>When customized and behind an Airlock Gateway (WAF), a \"URL Encryption Exception\" must be configured.</p>\n",
      optional = true,
      defaultValue = "ui/app/error/message",
      suggestedValues = "ui/app/error/message"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String errorpageUrl;
   static final String ERROR_PAGE_URL_PROPERTY = "errorpageUrl";
   @IntegerProperty(
      description = "The maximum content-length in bytes for an HTTP Request that will be allowed.<br/>This avoids unnecessary parsing of very long payloads, avoiding DoS attacks. Set to 0 (zero) to disable this check.",
      optional = true,
      defaultValue = 16384,
      minValue = 0,
      exampleValues = {0, 16384}
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private int maxContentLength;
   @PluginProperty(
      displayName = "XML Signature Keystore Provider",
      description = "The keystore provider to use for XML signatures and encryption.<br/>If this IAM instance is only used as a service provider and does <b>not</b> make use of any signature nor encryption, the special \"SAML No Cert Key Provider\" can be used which does not require any keystores. Notice though that even a simple service provider should make use of signatures, especially with SP-initiated SSO and with Single-Logout (SLO).",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private SamlFederationConfig.ISamlKeystoreProvider xmlSignatureKeystoreProvider;
   @StringProperty(
      displayName = "XML Canonicalization Algorithm",
      description = "XML canonicalization algorithm. Used for SAML XML signature generation and verification.",
      optional = true,
      defaultValue = "http://www.w3.org/2001/10/xml-exc-c14n#",
      allowedValues = {
            "http://www.w3.org/2001/10/xml-exc-c14n#",
            "http://www.w3.org/2001/10/xml-exc-c14n#WithComments",
            "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
            "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
      }
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private String xmlCanonicalizationAlgorithm;
   @StringProperty(
      displayName = "XML Signature Algorithm",
      description = "XML signature algorithm. Used for SAML XML and query signature generation.<br/>The (deprecated) value \"SHA1 (automatic RSA/DSA)\" automatically chooses \"http://www.w3.org/2000/09/xmldsig#rsa-sha1\" or \"http://www.w3.org/2000/09/xmldsig#dsa-sha1\" depending on the type of the key found in the keystore. However please use a more secure hash instead, as SHA-1 is not considered to be secure.",
      optional = true,
      defaultValue = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
      allowedValues = {
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
            "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
            "http://www.w3.org/2000/09/xmldsig#dsa-sha1",
            "SHA1 (automatic RSA/DSA)",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-md5"
      }
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private String xmlSignatureAlgorithm;
   @StringListProperty(
      displayName = "Allowed XML Signature Algorithm(s)",
      description = "Allowed XML signature algorithm(s) used for XML and query signature verification.",
      optional = true,
      minElements = 1,
      defaultValue = {
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
      },
      allowedValues = {
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
            "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
            "http://www.w3.org/2000/09/xmldsig#dsa-sha1",
            "http://www.w3.org/2001/04/xmldsig-more#rsa-md5"
      },
      exampleElements = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private List<String> allowedXmlSignatureAlgorithms;
   @StringProperty(
      displayName = "XML Signature Digest Method",
      description = "XML signature digest method. Used for SAML XML signature generation and verification.",
      optional = true,
      defaultValue = "http://www.w3.org/2001/04/xmlenc#sha256",
      allowedValues = {
            "http://www.w3.org/2001/04/xmlenc#sha512",
            "http://www.w3.org/2001/04/xmlenc#sha256",
            "http://www.w3.org/2000/09/xmldsig#sha1",
            "http://www.w3.org/2001/04/xmlenc#ripemd160"
      }
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private String xmlSignatureDigestMethod;
   @StringProperty(
      displayName = "XML Transformation Algorithm",
      description = "XML transformation algorithm. Used for SAML XML signature generation and verification.",
      optional = true,
      defaultValue = "http://www.w3.org/2001/10/xml-exc-c14n#",
      allowedValues = {
            "http://www.w3.org/2001/10/xml-exc-c14n#",
            "http://www.w3.org/2001/10/xml-exc-c14n#WithComments",
            "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
            "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
            "http://www.w3.org/TR/1999/REC-xslt-19991116",
            "http://www.w3.org/2000/09/xmldsig#base64",
            "http://www.w3.org/TR/1999/REC-xpath-19991116",
            "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
            "http://www.w3.org/TR/2001/WD-xptr-20010108",
            "http://www.w3.org/2002/04/xmldsig-filter2",
            "http://www.w3.org/2002/06/xmldsig-filter2",
            "http://www.nue.et-inf.uni-siegen.de/~geuer-pollmann/#xpathFilter"
      }
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private String xmlTransformationAlgorithm;
   @PluginProperty(
      displayName = "Key Transport Algorithm",
      description = "The Key Transport algorithm used to encrypt and decrypt keys.",
      optional = true,
      defaultValue = SamlRsaOaepKeyTransportAlgorithmConfig.class
   )
   @GroupProperty(groupIdentifier = "Signature Settings")
   private SamlKeyTransportAlgorithmConfig keyTransportAlgorithm;
   @StringProperty(
      description = "Used to decode a possibly encrypted password from a file to access a keystore and the keys contained. Will also be used to decode the configured BASIC AUTH password.<br/>The default implementation also supports encrypted passwords using the \"[ENC]\" prefix.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.Saml2PasswordDecoder"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String passwordDecoder;
   private static final String PASSWORD_DECODER_PROPERTY = "passwordDecoder";
   @StringProperty(
      description = "Defines the class name of the DebugProvider to use to create instances used for debug logging.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.DebugProviderImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String debugProvider;
   private static final String DEBUG_PROVIDER_PROPERTY = "debugProvider";
   @StringProperty(
      description = "Specifies the implementation for the Logger interface to log errors and special access logs.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.LoggerImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String logProvider;
   private static final String LOG_PROVIDER_PROPERTY = "logProvider";
   @StringProperty(
      description = "Specifies the implementation of the ConfigurationInstance providing all library-wide settings as well as specific SAML properties and entities.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.configuration.ConfigurationInstanceImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String configurationProvider;
   private static final String CONFIGURATION_PROVIDER_PROPERTY = "configurationProvider";
   @StringProperty(
      description = "Specifies the default implementation for the DataStoreProvider interface providing access to an optional data store holding user data to include in an assertion.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.DataStoreProviderImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String datastoreProvider;
   private static final String DATASTORE_PROVIDER_PROPERTY = "datastoreProvider";
   @StringProperty(
      description = "Specifies the implementation for the SessionProvider interface providing access to a federation session storing information about protocols used and service providers accessed for a specific authenticated user.",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.SessionProviderImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String sessionProvider;
   private static final String SESSION_PROVIDER_PROPERTY = "sessionProvider";
   @StringProperty(
      description = "Specifies the implementation for the IDPAuthnContextMapper interface which defines how the AuthnContext is created in the Assertion.",
      displayName = "IdP AuthnContext Mapper",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.IDPAuthnContextMapperImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String idpAuthnContextMapper;
   private static final String IDP_AUTHN_CONTEXT_MAPPER_PROPERTY = "idpAuthnContextMapper";
   @StringProperty(
      description = "Specifies the implementation for the IDPAccountMapper interface which defines how the NameID is created in the Assertion.",
      displayName = "IdP Account Mapper",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.IDPAccountMapperImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String idpAccountMapper;
   private static final String IDP_ACCOUNT_MAPPER_PROPERTY = "idpAccountMapper";
   @StringProperty(
      description = "Specifies the implementation for the IDPAttributeMapper interface which defines how the Attributes are created in the Assertion.",
      displayName = "IdP Attribute Mapper",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.IDPAttributeMapperImpl"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String idpAttributeMapper;
   private static final String IDP_ATTRIBUTE_MAPPER_PROPERTY = "idpAttributeMapper";
   @StringProperty(
      description = "Specifies the implementation of the SAML2ServiceProviderAdapter. The SP Adapter is called on certain events during SAMLv2 protocol processing on the Service Provider side.",
      displayName = "SP Adapter",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.Saml2ServiceProviderAdapter"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String spAdapter;
   private static final String SP_ADAPTER_PROPERTY = "spAdapter";
   @StringProperty(
      description = "Specifies the implementation for the SPAuthnContextMapper interface which defines how the AuthnContext is created in the Assertion.",
      displayName = "SP AuthnContext Mapper",
      optional = true,
      defaultValue = "com.airlock.iam.saml2.infrastructure.plugin.SPAuthnContextMapper"
   )
   @GroupProperty(groupIdentifier = "Plugin Settings")
   private String spAuthnContextMapper;
   private static final String SP_AUTHN_CONTEXT_MAPPER_PROPERTY = "spAuthnContextMapper";

   public URI getErrorPageUri() {
      return URI.create(this.errorpageUrl);
   }

   @AfterConfigActivation
   void prepareConfig() {
      this.propertyMapper.clear();

      for (SamlFederationConfig.FederationProperty prop : SamlFederationConfig.FederationProperty.values()) {
         this.propertyMapper.put(prop.getFederationPropertiesKey(), prop);
      }
   }

   @Nullable
   public String getProperty(String key) {
      if (StringUtils.isBlank(key)) {
         return null;
      } else if (staticConfiguration.containsKey(key)) {
         return staticConfiguration.get(key);
      } else {
         return this.propertyMapper.containsKey(key) ? this.propertyMapper.get(key).getValue(this) : null;
      }
   }

   public String getSpAuthnContextMapper() {
      return this.spAuthnContextMapper;
   }

   public String getSpAdapter() {
      return this.spAdapter;
   }

   public String getIdpAttributeMapper() {
      return this.idpAttributeMapper;
   }

   public String getIdpAccountMapper() {
      return this.idpAccountMapper;
   }

   public String getIdpAuthnContextMapper() {
      return this.idpAuthnContextMapper;
   }

   public List<String> getAllowedXmlSignatureAlgorithms() {
      return this.allowedXmlSignatureAlgorithms;
   }

   @ConfigurationValidator
   static void checkPluginClassesExistence(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      if (validationEnvironment == Environment.CURRENT_VM) {
         checkClassExistence("passwordDecoder", config, env, context);
         checkClassExistence("debugProvider", config, env, context);
         checkClassExistence("logProvider", config, env, context);
         checkClassExistence("configurationProvider", config, env, context);
         checkClassExistence("datastoreProvider", config, env, context);
         checkClassExistence("sessionProvider", config, env, context);
         checkClassExistence("idpAuthnContextMapper", config, env, context);
         checkClassExistence("idpAccountMapper", config, env, context);
         checkClassExistence("idpAttributeMapper", config, env, context);
         checkClassExistence("spAdapter", config, env, context);
         checkClassExistence("spAuthnContextMapper", config, env, context);
      }
   }

   private static void checkClassExistence(String propertyName, PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context) throws ConfigurationException {
      String className = StringPropertyValueReader.effectiveStringConfigValue(config, propertyName, env, context);
      if (className != null) {
         try {
            Class.forName(className, false, SamlFederationConfig.class.getClassLoader());
         } catch (ClassNotFoundException e) {
            throw new PropertyConstraintViolationException(propertyName, config, env, context, "Cannot load class \"%s\"".formatted(className));
         } catch (LinkageError e) {
            throw new PropertyConstraintViolationException(
               propertyName, config, env, context, "Cannot load class \"%s\": %s".formatted(className, e.getMessage())
            );
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static SamlFederationConfig.SamlFederationConfigBuilder builder() {
      return new SamlFederationConfig.SamlFederationConfigBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public SamlFederationConfig(
      String errorpageUrl,
      int maxContentLength,
      SamlFederationConfig.ISamlKeystoreProvider xmlSignatureKeystoreProvider,
      String xmlCanonicalizationAlgorithm,
      String xmlSignatureAlgorithm,
      List<String> allowedXmlSignatureAlgorithms,
      String xmlSignatureDigestMethod,
      String xmlTransformationAlgorithm,
      SamlKeyTransportAlgorithmConfig keyTransportAlgorithm,
      String passwordDecoder,
      String debugProvider,
      String logProvider,
      String configurationProvider,
      String datastoreProvider,
      String sessionProvider,
      String idpAuthnContextMapper,
      String idpAccountMapper,
      String idpAttributeMapper,
      String spAdapter,
      String spAuthnContextMapper
   ) {
      this.errorpageUrl = errorpageUrl;
      this.maxContentLength = maxContentLength;
      this.xmlSignatureKeystoreProvider = xmlSignatureKeystoreProvider;
      this.xmlCanonicalizationAlgorithm = xmlCanonicalizationAlgorithm;
      this.xmlSignatureAlgorithm = xmlSignatureAlgorithm;
      this.allowedXmlSignatureAlgorithms = allowedXmlSignatureAlgorithms;
      this.xmlSignatureDigestMethod = xmlSignatureDigestMethod;
      this.xmlTransformationAlgorithm = xmlTransformationAlgorithm;
      this.keyTransportAlgorithm = keyTransportAlgorithm;
      this.passwordDecoder = passwordDecoder;
      this.debugProvider = debugProvider;
      this.logProvider = logProvider;
      this.configurationProvider = configurationProvider;
      this.datastoreProvider = datastoreProvider;
      this.sessionProvider = sessionProvider;
      this.idpAuthnContextMapper = idpAuthnContextMapper;
      this.idpAccountMapper = idpAccountMapper;
      this.idpAttributeMapper = idpAttributeMapper;
      this.spAdapter = spAdapter;
      this.spAuthnContextMapper = spAuthnContextMapper;
   }

   @SuppressFBWarnings(justification = "generated code")
   public SamlFederationConfig() {
   }

   public enum FederationProperty {
      XMLSIG_KEYPROVIDER("com.sun.identity.saml.xmlsig.keyprovider.class") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureKeystoreProvider.getImplementationClass().getName();
         }
      },
      XMLSIG_KEYSTORE("com.sun.identity.saml.xmlsig.keystore") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureKeystoreProvider.getKeystore().getPath();
         }
      },
      XMLSIG_KEYSTORETYPE("com.sun.identity.saml.xmlsig.storetype") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureKeystoreProvider.getKeystoreType();
         }
      },
      XMLSIG_KEYSTOREPASS("com.sun.identity.saml.xmlsig.storepass") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureKeystoreProvider.getKeystorePasswordFile().getPath();
         }
      },
      XMLSIG_KEYPASS("com.sun.identity.saml.xmlsig.keypass") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureKeystoreProvider.getKeystorePrivateKeyPasswordFile().getPath();
         }
      },
      PASSWORD_DECODER("com.sun.identity.saml.xmlsig.passwordDecoder") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.passwordDecoder;
         }
      },
      ERRORPAGE_URL("com.sun.identity.saml.errorpage.url") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.errorpageUrl;
         }
      },
      DEBUG_PROVIDER("com.sun.identity.util.debug.provider") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.debugProvider;
         }
      },
      LOG_PROVIDER("com.sun.identity.plugin.log.class") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.logProvider;
         }
      },
      CONFIG_PROVIDER("com.sun.identity.plugin.configuration.class") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.configurationProvider;
         }
      },
      DATASTORE_PROVIDER("com.sun.identity.plugin.datastore.class.default") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.datastoreProvider;
         }
      },
      SESSION_PROVIDER("com.sun.identity.plugin.session.class") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.sessionProvider;
         }
      },
      XML_C14N_METHOD("com.sun.identity.saml.xmlsig.c14nMethod") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlCanonicalizationAlgorithm;
         }
      },
      XML_SIGNATURE_ALGORITHM("com.sun.identity.saml.xmlsig.xmlSigAlgorithm") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return "SHA1 (automatic RSA/DSA)".equals(config.xmlSignatureAlgorithm) ? null : config.xmlSignatureAlgorithm;
         }
      },
      ALLOWED_XML_SIGNATURE_ALGORITHMS("allowedXmlAlgorithms") {
         @Override
         public String getValue(SamlFederationConfig config) {
            List<String> algorithms = config.getAllowedXmlSignatureAlgorithms();
            return SignatureAlgorithm.convertAllowedAlgosListToString(algorithms);
         }
      },
      XML_DIGEST_METHOD("digestMethod") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlSignatureDigestMethod;
         }
      },
      XML_TRANSFORMATION_ALGORITHM("com.sun.identity.saml.xmlsig.transformAlg") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.xmlTransformationAlgorithm;
         }
      },
      KEY_TRANSPORT_ALGORITHM("keyTransportAlgorithm") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return config.keyTransportAlgorithm instanceof SamlRsaOaepKeyTransportAlgorithmConfig
               ? SamlEncryptionProvider.KeyTransportAlgorithm.RSA_OAEP.getAlgorithm()
               : SamlEncryptionProvider.KeyTransportAlgorithm.RSA_15.getAlgorithm();
         }
      },
      RSA_OAEP_PARAMS("rsaOaepParams") {
         @Override
         public String getValue(SamlFederationConfig config) {
            if (config.keyTransportAlgorithm instanceof SamlRsaOaepKeyTransportAlgorithmConfig algorithm) {
               return algorithm.getOaepParams().orElse(null);
            } else {
               throw new IllegalStateException(
                  String.format(
                     "Wrong key transport algorithm %s. Should be set to %s.",
                     config.keyTransportAlgorithm.getClass().getSimpleName(),
                     SamlRsaOaepKeyTransportAlgorithmConfig.class.getSimpleName()
                  )
               );
            }
         }
      },
      MAX_CONTENT_LENGTH("com.sun.identity.saml.request.maxContentLength") {
         @Override
         public String getValue(SamlFederationConfig config) {
            return Integer.toString(config.maxContentLength);
         }
      };

      private final String federationPropertiesKey;

      FederationProperty(String federationPropertiesKey) {
         this.federationPropertiesKey = federationPropertiesKey;
      }

      public String getFederationPropertiesKey() {
         return this.federationPropertiesKey;
      }

      public abstract String getValue(SamlFederationConfig var1);
   }

   public interface ISamlKeystoreProvider {
      Class<? extends KeyProvider> getImplementationClass();

      File getKeystore();

      String getKeystoreType();

      File getKeystorePasswordFile();

      File getKeystorePrivateKeyPasswordFile();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class SamlFederationConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String errorpageUrl;
      @SuppressFBWarnings(justification = "generated code")
      private int maxContentLength;
      @SuppressFBWarnings(justification = "generated code")
      private SamlFederationConfig.ISamlKeystoreProvider xmlSignatureKeystoreProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String xmlCanonicalizationAlgorithm;
      @SuppressFBWarnings(justification = "generated code")
      private String xmlSignatureAlgorithm;
      @SuppressFBWarnings(justification = "generated code")
      private List<String> allowedXmlSignatureAlgorithms;
      @SuppressFBWarnings(justification = "generated code")
      private String xmlSignatureDigestMethod;
      @SuppressFBWarnings(justification = "generated code")
      private String xmlTransformationAlgorithm;
      @SuppressFBWarnings(justification = "generated code")
      private SamlKeyTransportAlgorithmConfig keyTransportAlgorithm;
      @SuppressFBWarnings(justification = "generated code")
      private String passwordDecoder;
      @SuppressFBWarnings(justification = "generated code")
      private String debugProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String logProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String configurationProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String datastoreProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String sessionProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String idpAuthnContextMapper;
      @SuppressFBWarnings(justification = "generated code")
      private String idpAccountMapper;
      @SuppressFBWarnings(justification = "generated code")
      private String idpAttributeMapper;
      @SuppressFBWarnings(justification = "generated code")
      private String spAdapter;
      @SuppressFBWarnings(justification = "generated code")
      private String spAuthnContextMapper;

      @SuppressFBWarnings(justification = "generated code")
      SamlFederationConfigBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder errorpageUrl(String errorpageUrl) {
         this.errorpageUrl = errorpageUrl;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder maxContentLength(int maxContentLength) {
         this.maxContentLength = maxContentLength;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder xmlSignatureKeystoreProvider(
         SamlFederationConfig.ISamlKeystoreProvider xmlSignatureKeystoreProvider
      ) {
         this.xmlSignatureKeystoreProvider = xmlSignatureKeystoreProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder xmlCanonicalizationAlgorithm(String xmlCanonicalizationAlgorithm) {
         this.xmlCanonicalizationAlgorithm = xmlCanonicalizationAlgorithm;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder xmlSignatureAlgorithm(String xmlSignatureAlgorithm) {
         this.xmlSignatureAlgorithm = xmlSignatureAlgorithm;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder allowedXmlSignatureAlgorithms(List<String> allowedXmlSignatureAlgorithms) {
         this.allowedXmlSignatureAlgorithms = allowedXmlSignatureAlgorithms;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder xmlSignatureDigestMethod(String xmlSignatureDigestMethod) {
         this.xmlSignatureDigestMethod = xmlSignatureDigestMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder xmlTransformationAlgorithm(String xmlTransformationAlgorithm) {
         this.xmlTransformationAlgorithm = xmlTransformationAlgorithm;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder keyTransportAlgorithm(SamlKeyTransportAlgorithmConfig keyTransportAlgorithm) {
         this.keyTransportAlgorithm = keyTransportAlgorithm;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder passwordDecoder(String passwordDecoder) {
         this.passwordDecoder = passwordDecoder;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder debugProvider(String debugProvider) {
         this.debugProvider = debugProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder logProvider(String logProvider) {
         this.logProvider = logProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder configurationProvider(String configurationProvider) {
         this.configurationProvider = configurationProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder datastoreProvider(String datastoreProvider) {
         this.datastoreProvider = datastoreProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder sessionProvider(String sessionProvider) {
         this.sessionProvider = sessionProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder idpAuthnContextMapper(String idpAuthnContextMapper) {
         this.idpAuthnContextMapper = idpAuthnContextMapper;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder idpAccountMapper(String idpAccountMapper) {
         this.idpAccountMapper = idpAccountMapper;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder idpAttributeMapper(String idpAttributeMapper) {
         this.idpAttributeMapper = idpAttributeMapper;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder spAdapter(String spAdapter) {
         this.spAdapter = spAdapter;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig.SamlFederationConfigBuilder spAuthnContextMapper(String spAuthnContextMapper) {
         this.spAuthnContextMapper = spAuthnContextMapper;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SamlFederationConfig build() {
         return new SamlFederationConfig(
            this.errorpageUrl,
            this.maxContentLength,
            this.xmlSignatureKeystoreProvider,
            this.xmlCanonicalizationAlgorithm,
            this.xmlSignatureAlgorithm,
            this.allowedXmlSignatureAlgorithms,
            this.xmlSignatureDigestMethod,
            this.xmlTransformationAlgorithm,
            this.keyTransportAlgorithm,
            this.passwordDecoder,
            this.debugProvider,
            this.logProvider,
            this.configurationProvider,
            this.datastoreProvider,
            this.sessionProvider,
            this.idpAuthnContextMapper,
            this.idpAccountMapper,
            this.idpAttributeMapper,
            this.spAdapter,
            this.spAuthnContextMapper
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "SamlFederationConfig.SamlFederationConfigBuilder(errorpageUrl="
            + this.errorpageUrl
            + ", maxContentLength="
            + this.maxContentLength
            + ", xmlSignatureKeystoreProvider="
            + this.xmlSignatureKeystoreProvider
            + ", xmlCanonicalizationAlgorithm="
            + this.xmlCanonicalizationAlgorithm
            + ", xmlSignatureAlgorithm="
            + this.xmlSignatureAlgorithm
            + ", allowedXmlSignatureAlgorithms="
            + this.allowedXmlSignatureAlgorithms
            + ", xmlSignatureDigestMethod="
            + this.xmlSignatureDigestMethod
            + ", xmlTransformationAlgorithm="
            + this.xmlTransformationAlgorithm
            + ", keyTransportAlgorithm="
            + this.keyTransportAlgorithm
            + ", passwordDecoder="
            + this.passwordDecoder
            + ", debugProvider="
            + this.debugProvider
            + ", logProvider="
            + this.logProvider
            + ", configurationProvider="
            + this.configurationProvider
            + ", datastoreProvider="
            + this.datastoreProvider
            + ", sessionProvider="
            + this.sessionProvider
            + ", idpAuthnContextMapper="
            + this.idpAuthnContextMapper
            + ", idpAccountMapper="
            + this.idpAccountMapper
            + ", idpAttributeMapper="
            + this.idpAttributeMapper
            + ", spAdapter="
            + this.spAdapter
            + ", spAuthnContextMapper="
            + this.spAuthnContextMapper
            + ")";
      }
   }
}
