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

com.nimbusds.openid.connect.provider.spi.reg.statement.Configuration Maven / Gradle / Ivy

There is a newer version: 2.3
Show newest version
package com.nimbusds.openid.connect.provider.spi.reg.statement;


import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

import com.thetransactioncompany.util.PropertyFilter;
import com.thetransactioncompany.util.PropertyParseException;
import com.thetransactioncompany.util.PropertyRetriever;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.nimbusds.common.config.ConfigurationException;
import com.nimbusds.common.config.LoggableConfiguration;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.oauth2.sdk.util.StringUtils;


/**
 * Software statement verifier configuration. It is typically derived from a 
 * Java key / value properties file. The configuration is stored as public 
 * fields which become immutable (final) after their initialisation.
 *
 * 

Example configuration properties: * *

 * op.ssv.enable=true
 * op.ssv.issuer=https://publisher.example.com
 * op.ssv.issuerJWKSetURL=https://publisher.example.com/jwks.json
 * op.ssv.jwsAlgorithms=RS256,PS256
 * op.ssv.connectTimeout=250
 * op.ssv.readTimeout=250
 * op.ssv.registrationAccessToken=ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
 * op.ssv.additionalRequiredClaims=
 * op.ssv.logClaims=iss
 * op.ssv.clientX509Certificate.require=false
 * op.ssv.clientX509Certificate.rootDN=
 * op.ssv.requestType=JSON
 * op.ssv.requestJWT.jwkSetSource=
 * op.ssv.requestJWT.jwsAlgorithms=
 * op.ssv.requestJWT.requiredClaims=
 * op.ssv.transforms.remove=iss,iat,jti
 * op.ssv.transforms.rename.software_jwks_endpoint=jwks_uri
 * op.ssv.transforms.rename.software_client_name=client_name
 * op.ssv.transforms.moveIntoData=org_id,org_contacts
 * 
*/ public final class Configuration implements LoggableConfiguration { /** * The configuration file path. */ public static final String FILE_PATH = "/WEB-INF/softwareStatementVerifier.properties"; /** * The default properties prefix. */ public static final String DEFAULT_PREFIX = "op.ssv."; /** * Enables / disables the software statements verifier. Disabled by * default. * *

Property key: [prefix]enable */ public final boolean enable; /** * The software statements issuer. * *

Property key: [prefix]issuer */ public final Issuer issuer; /** * The URL where the software statements issuer publishes its public * JWK set. * *

Property key: [prefix]issuerJWKSetURL */ public final URL issuerJWKSetURL; /** * The accepted JWS algorithms for the software statements. * *

Property key: [prefix]jwsAlgorithms */ public final Set jwsAlgorithms; /** * The timeout in milliseconds for establishing HTTP connections. If * zero the underlying HTTP client library will determine the timeout. * *

Property key: [prefix]httpConnectTimeout */ public final int httpConnectTimeout; /** * The timeout in milliseconds for obtaining HTTP responses after * connection. If zero the underlying HTTP client library will * determine the timeout. * *

Property key: [prefix]readTimeout */ public final int httpReadTimeout; /** * An access token of type bearer (non-expiring) for accessing the * client registration endpoint. * *

Property key: [prefix]registrationAccessToken */ public final BearerAccessToken registrationAccessToken; /** * The names of any additional JWT claims that must be present in the * software statement, empty set if none. * *

Property key: [prefix]additionalRequiredClaims */ public final Set additionalRequiredClaims; /** * Names of software statement claims to log at INFO level. * *

Property key: [prefix]logClaims */ public final Set logClaims; /** * If {@code true} the HTTP POST request must include a client X.509 * certificate validated by the TLS terminator / reverse proxy. The * default value is {@code false}. * *

Property key: [prefix]clientX509Certificate.require */ public final boolean clientX509Certificate_require; /** * The required root DN of the client X.509 certificates, if client * certificates are required. * *

Property key: [prefix]clientX509Certificate.rootDN */ public final String clientX509Certificate_rootDN; /** * The accepted HTTP POST request type. * *

Property key: [prefix]requestType */ public final RequestType requestType; /** * The JWK set source for validating signed request JWTs. * *

Property key: [prefix]requestJWT.jwkSetSource */ public final JWKSetSource requestJWT_jwkSetSource; /** * The accepted JWS algorithms for the signed request JWTs. * *

Property key: [prefix]requestJWT.jwsAlgorithms */ public final Set requestJWT_jwsAlgorithms; /** * The names of the JWT claims that must be present in the signed * request JWT, empty set if none. * *

Property key: [prefix]requestJWT.requiredClaims */ public final Set requestJWT_requiredClaims; /** * List of names of top-level JSON object members to be removed from * the merged client metadata. * *

Property key: [prefix]transforms.remove */ public final List transforms_remove; /** * Map of names of top-level JSON object members to be renamed in the * merged client metadata. * *

Property key: [prefix]transforms.rename.[old-member-name]=[new-member-name] */ public final Map transforms_rename; /** * List of names of top-level JSON object members in the merged client * metadata to be moved into the "data" JSON object member. * *

Property key: [prefix]transforms.moveIntoData */ public final List transforms_moveIntoData; /** * Scope rules, keyed by rule name. * *

Property key: [prefix]scopeRules.* */ public final Map scopeRules; /** * Creates a new software statement verifier configuration from the * specified properties. System property override is enabled. * * @param props The properties. Must not be {@code null}. * * @throws ConfigurationException On a missing or invalid property. */ public Configuration(final Properties props) throws ConfigurationException { var pr = new PropertyRetriever(props, true); try { enable = pr.getOptBoolean(DEFAULT_PREFIX + "enable", false); if (! enable) { issuer = null; issuerJWKSetURL = null; jwsAlgorithms = Collections.emptySet(); httpConnectTimeout = 0; httpReadTimeout = 0; registrationAccessToken = null; additionalRequiredClaims = Collections.emptySet(); logClaims = Collections.emptySet(); clientX509Certificate_require = false; clientX509Certificate_rootDN = null; requestType = RequestType.JSON; requestJWT_jwkSetSource = null; requestJWT_jwsAlgorithms = Collections.emptySet(); requestJWT_requiredClaims = Collections.emptySet(); transforms_remove = Collections.emptyList(); transforms_rename = Collections.emptyMap(); transforms_moveIntoData = Collections.emptyList(); scopeRules = Collections.emptyMap(); return; } issuer = new Issuer(pr.getString(DEFAULT_PREFIX + "issuer")); issuerJWKSetURL = pr.getURL(DEFAULT_PREFIX + "issuerJWKSetURL"); var algorithms = new HashSet(); for (var algName: pr.getStringList(DEFAULT_PREFIX + "jwsAlgorithms")) { algorithms.add(JWSAlgorithm.parse(algName)); } jwsAlgorithms = Collections.unmodifiableSet(algorithms); httpConnectTimeout = pr.getInt(DEFAULT_PREFIX + "connectTimeout"); httpReadTimeout = pr.getInt(DEFAULT_PREFIX + "readTimeout"); registrationAccessToken = new BearerAccessToken(pr.getString(DEFAULT_PREFIX + "registrationAccessToken")); additionalRequiredClaims = new HashSet<>(pr.getOptStringList(DEFAULT_PREFIX + "additionalRequiredClaims", Collections.emptyList())); logClaims = new LinkedHashSet<>(pr.getOptStringList(DEFAULT_PREFIX + "logClaims", List.of("iss"))); clientX509Certificate_require = pr.getOptBoolean(DEFAULT_PREFIX + "clientX509Certificate.require", false); if (clientX509Certificate_require) { clientX509Certificate_rootDN = pr.getOptString(DEFAULT_PREFIX + "clientX509Certificate.rootDN", null); } else { clientX509Certificate_rootDN = null; } requestType = pr.getOptEnum(DEFAULT_PREFIX + "requestType", RequestType.class, RequestType.JSON); if (requestType.equals(RequestType.JWT)) { try { requestJWT_jwkSetSource = new JWKSetSource(pr.getURI(DEFAULT_PREFIX + "requestJWT.jwkSetSource")); } catch (URISyntaxException e) { throw new PropertyParseException(e.getMessage(), DEFAULT_PREFIX + "requestJWT.jwkSetSource"); } algorithms = new HashSet<>(); for (var algName: pr.getStringList(DEFAULT_PREFIX + "requestJWT.jwsAlgorithms")) { algorithms.add(JWSAlgorithm.parse(algName)); } requestJWT_jwsAlgorithms = Collections.unmodifiableSet(algorithms); requestJWT_requiredClaims = new HashSet<>(pr.getOptStringList(DEFAULT_PREFIX + "requestJWT.requiredClaims", Collections.emptyList())); } else { requestJWT_jwkSetSource = null; requestJWT_jwsAlgorithms = Collections.emptySet(); requestJWT_requiredClaims = Collections.emptySet(); } transforms_remove = pr.getOptStringList(DEFAULT_PREFIX + "transforms.remove", Collections.emptyList()); var mergedProps = new Properties(); mergedProps.putAll(props); mergedProps.putAll(System.getProperties()); var renameProps = PropertyFilter.filterWithPrefix(DEFAULT_PREFIX + "transforms.rename.", mergedProps); var renameMap = new HashMap(); for (var propName: renameProps.stringPropertyNames()) { var oldMemberName = propName.substring((DEFAULT_PREFIX + "transforms.rename.").length()); var newMemberName = renameProps.getProperty(propName); if (StringUtils.isNotBlank(oldMemberName) && StringUtils.isNotBlank(newMemberName)) { renameMap.put(oldMemberName, newMemberName); } } transforms_rename = Collections.unmodifiableMap(renameMap); transforms_moveIntoData = pr.getOptStringList(DEFAULT_PREFIX + "transforms.moveIntoData", Collections.emptyList()); Map scopeRuleMap = new HashMap<>(); var scopeRulesProps = PropertyFilter.filterWithPrefix(DEFAULT_PREFIX + "scopeRules.", mergedProps); for (var propName: scopeRulesProps.stringPropertyNames()) { if (propName.startsWith(DEFAULT_PREFIX + "scopeRules.") && propName.endsWith(".scope")) { var ruleName = propName.substring( (DEFAULT_PREFIX + "scopeRules.").length(), propName.lastIndexOf(".scope") ); var scope = Scope.parse(pr.getString(propName)); var jsonPath = pr.getString(DEFAULT_PREFIX + "scopeRules." + ruleName + ".jsonPath"); scopeRuleMap.put(ruleName, new ScopeRule(scope, jsonPath)); } } scopeRules = Collections.unmodifiableMap(scopeRuleMap); } catch (PropertyParseException e) { throw new ConfigurationException(e.getMessage() + ": Property: " + e.getPropertyKey()); } } /** * Logs the configuration details at INFO level. Properties that may * adversely affect security are logged at WARN level. */ @Override public void log() { Logger log = LogManager.getLogger("MAIN"); log.info("[SSV0000] Software statement verifier configuration:"); log.info("[SSV0001] Software statement verifier enabled: {}", enable); if (! enable) { return; } log.info("[SSV0002] Software statement issuer: {}", issuer); if ("https".equalsIgnoreCase(issuerJWKSetURL.getProtocol())) { log.info("[SSV0003] Software statement issuer JWK set URL: {}", issuerJWKSetURL); } else { log.warn("[SSV0003] Software statement issuer JWK set URL (unsecured, consider using HTTPS): {}", issuerJWKSetURL); } log.info("[SSV0011] Software statement JWS algorithms: {}", jwsAlgorithms); log.info("[SSV0004] HTTP connect timeout: {} ms", httpConnectTimeout); log.info("[SSV0005] HTTP read timeout: {} ms", httpReadTimeout); log.info("[SSV0006] Registration access token configured: {}", registrationAccessToken != null); log.info("[SSV0007] Additional required software statement JWT claims: {}", additionalRequiredClaims != null ? additionalRequiredClaims : "none"); log.info("[SSV0018] Software statement claims to log at INFO level under SSV0100: {}", logClaims); log.info("[SSV0008] Client X.509 certificate required: {}", clientX509Certificate_require); if (clientX509Certificate_require) { log.info("[SSV0014] Client X.509 certificate root DN: {}", clientX509Certificate_rootDN != null ? clientX509Certificate_rootDN : "not specified"); } log.info("[SSV0009] Accepted registration request type: {}", requestType); if (requestType.equals(RequestType.JWT)) { log.info("[SSV0010] JWK set source for validating registration request JWTs: {}", requestJWT_jwkSetSource); log.info("[SSV0012] Registration request JWS algorithms: {}", requestJWT_jwsAlgorithms); log.info("[SSV0013] Required registration request JWT claims: {}", requestJWT_requiredClaims != null ? requestJWT_requiredClaims : "none"); } log.info("[SSV0015] Merged client metadata transforms: Rename map: {}", transforms_rename); log.info("[SSV0016] Merged client metadata transforms: Move into \"data\" list: {}", transforms_moveIntoData); log.info("[SSV0017] Merged client metadata transforms: Remove list: {}", transforms_remove); log.info("[SSV0019] Scope rules: {}", scopeRules); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy