diff --git a/esp/services/esdl_svc_engine/esdl_binding.cpp b/esp/services/esdl_svc_engine/esdl_binding.cpp index 8e2f11eab7d..6c3a74103a4 100755 --- a/esp/services/esdl_svc_engine/esdl_binding.cpp +++ b/esp/services/esdl_svc_engine/esdl_binding.cpp @@ -747,9 +747,9 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service) continue; GatewaysCacheEntry& gce = m_methodGatewaysCache[method]; std::set uniqueNames; - bool updateInlines = gateways->getPropBool("@updateInlineUrls"); + bool updateInlines = gateways->getPropBool("@updateInline"); bool doLegacyTransform = !isEmptyString(gateways->queryProp("@legacyTransformTarget")); - Secrets secrets; + TransactionSecrets secrets; Owned gwIt(gateways->getElements("Gateway")); ForEach(*gwIt) { @@ -774,10 +774,11 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service) if (strncmp(url, gwLocalSecretPrefix, gwLocalSecretPrefixLength) == 0) { handler.setown(createLocalSecretGateway(gw, name, url)); + gce.targetContext[key].set(handler.get()); + // sanity check that a secret is identified; the updater is not to be retained GatewayUpdaters updaters; Owned updater(handler->getUpdater(updaters, secrets)); updater.clear(); - gce.targetContext[key].set(handler.get()); } else if (hasHttpPrefix(url)) { @@ -1393,7 +1394,7 @@ EsdlServiceImpl::IUpdatableGateway* EsdlServiceImpl::createInlineGateway(const I return new CLegacyUrlGateway(gw, gwName, gwUrl); } -void EsdlServiceImpl::applyGatewayUpdates(IPTreeIterator& gwIt, const UpdatableGateways& updatables, GatewayUpdaters& updaters, Secrets& secrets) const +void EsdlServiceImpl::applyGatewayUpdates(IPTreeIterator& gwIt, const UpdatableGateways& updatables, GatewayUpdaters& updaters, TransactionSecrets& secrets) const { ForEach(gwIt) { @@ -1784,7 +1785,7 @@ void EsdlServiceImpl::prepareFinalRequest(IEspContext &context, GatewaysCache::const_iterator mgcIt = m_methodGatewaysCache.find(mthName); Owned gwIt; GatewayUpdaters updaters; - Secrets secrets; + TransactionSecrets secrets; if (tgtctx) { if (mgcIt != m_methodGatewaysCache.end() && !mgcIt->second.targetContext.empty()) @@ -1833,7 +1834,6 @@ void EsdlServiceImpl::prepareFinalRequest(IEspContext &context, // Temporarily add the closing tag so we have valid // XML to transform the gateways Owned soapTree = createPTreeFromXMLString(reqProcessed.append(""), ipt_ordered); - xpath.replaceString("{$query}", tgtQueryName); xpath.replaceString("{$method}", mthName); xpath.replaceString("{$service}", srvdef.queryName()); @@ -1903,7 +1903,7 @@ EsdlServiceImpl::~EsdlServiceImpl() } } -IPTree* EsdlServiceImpl::Secrets::getVaultSecret(const char* category, const char* vaultId, const char* name) +IPTree* EsdlServiceImpl::TransactionSecrets::getVaultSecret(const char* category, const char* vaultId, const char* name) { Owned secret(lookup(category, vaultId, name)); if (!secret) @@ -1915,7 +1915,7 @@ IPTree* EsdlServiceImpl::Secrets::getVaultSecret(const char* category, const cha return secret.getClear(); } -IPTree* EsdlServiceImpl::Secrets::getSecret(const char* category, const char* name) +IPTree* EsdlServiceImpl::TransactionSecrets::getSecret(const char* category, const char* name) { Owned secret(lookup(category, "", name)); if (!secret) @@ -1927,7 +1927,7 @@ IPTree* EsdlServiceImpl::Secrets::getSecret(const char* category, const char* na return secret; } -IPTree* EsdlServiceImpl::Secrets::lookup(const char* category, const char* vaultId, const char* name) const +IPTree* EsdlServiceImpl::TransactionSecrets::lookup(const char* category, const char* vaultId, const char* name) const { Key key = std::make_tuple(category ? category : "", vaultId ? vaultId : "", name ? name : ""); Cache::const_iterator it = cache.find(key); @@ -1936,13 +1936,13 @@ IPTree* EsdlServiceImpl::Secrets::lookup(const char* category, const char* vault return nullptr; } -void EsdlServiceImpl::Secrets::store(IPTree& secret, const char* category, const char* vaultId, const char* name) +void EsdlServiceImpl::TransactionSecrets::store(IPTree& secret, const char* category, const char* vaultId, const char* name) { Key key = std::make_tuple(category ? category : "", vaultId ? vaultId : "", name ? name : ""); cache[key].set(&secret); } -EsdlServiceImpl::IGatewayUpdater* EsdlServiceImpl::CUpdatableGateway::getUpdater(GatewayUpdaters& updaters, Secrets& secrets) const +EsdlServiceImpl::IGatewayUpdater* EsdlServiceImpl::CUpdatableGateway::getUpdater(GatewayUpdaters& updaters, TransactionSecrets& secrets) const { GatewayUpdaters::iterator it = updaters.find(updatersKey); if (it != updaters.end()) @@ -1990,7 +1990,7 @@ bool EsdlServiceImpl::CUpdatableGateway::updateURLCredentials(StringBuffer& url, return false; } -EsdlServiceImpl::CLegacyUrlGateway* EsdlServiceImpl::CLegacyUrlGateway::getUpdater(Secrets&) const +EsdlServiceImpl::CLegacyUrlGateway* EsdlServiceImpl::CLegacyUrlGateway::getUpdater(TransactionSecrets&) const { return LINK(const_cast(this)); } @@ -2024,7 +2024,7 @@ void EsdlServiceImpl::CLocalSecretGateway::CUpdater::updateGateway(IPTree& gw, c entry->doUpdate(gw, *secret, requiredUsage); } -EsdlServiceImpl::CLocalSecretGateway::CUpdater::CUpdater(const CLocalSecretGateway& _entry, Secrets& secrets) +EsdlServiceImpl::CLocalSecretGateway::CUpdater::CUpdater(const CLocalSecretGateway& _entry, TransactionSecrets& secrets) { entry.set(&_entry); if (entry->vaultId.isEmpty()) @@ -2033,7 +2033,7 @@ EsdlServiceImpl::CLocalSecretGateway::CUpdater::CUpdater(const CLocalSecretGatew secret.setown(secrets.getVaultSecret("esp", entry->vaultId.str(), entry->secretName)); } -EsdlServiceImpl::IGatewayUpdater* EsdlServiceImpl::CLocalSecretGateway::getUpdater(Secrets& secrets) const +EsdlServiceImpl::IGatewayUpdater* EsdlServiceImpl::CLocalSecretGateway::getUpdater(TransactionSecrets& secrets) const { return new CUpdater(*this, secrets); } @@ -2067,7 +2067,7 @@ EsdlServiceImpl::CLocalSecretGateway::CLocalSecretGateway(const IPTree& gw, cons void EsdlServiceImpl::CLocalSecretGateway::doUpdate(IPTree& gw, const IPTree& secret, const char* requiredUsage) const { if (!isEmptyString(requiredUsage) && !secret.getPropBool(requiredUsage)) - throw makeStringExceptionV(-1, "gateway %s: '%s' does not allow '%s' usage", updatersKey.c_str(), secretId.str(), requiredUsage); + throw makeStringExceptionV(-1, "gateway %s: secret '%s' does not allow '%s' usage", updatersKey.c_str(), secretId.str(), requiredUsage); } void EsdlServiceImpl::CHttpConnectGateway::doUpdate(IPTree& gw, const IPTree& secret, const char* requiredUsage) const @@ -2075,10 +2075,13 @@ void EsdlServiceImpl::CHttpConnectGateway::doUpdate(IPTree& gw, const IPTree& se CLocalSecretGateway::doUpdate(gw, secret, requiredUsage); StringBuffer url; if (!secret.getProp("url", url.clear()) || url.isEmpty()) - throw makeStringExceptionV(-1, "gateway %s: '%s' missing required 'url' property; credential-only secrets not supported", gw.queryProp("@name"), secretId.str()); + throw makeStringExceptionV(-1, "gateway %s: secret '%s' missing required 'url' property; credential-only secrets not supported", gw.queryProp("@name"), secretId.str()); const char* username = secret.queryProp("username"); - if (isEmptyString(username) && !secret.getPropBool("omitCredentials")) - throw makeStringExceptionV(-1, "gateway %s: '%s' missing expected 'username' property; set 'omitCredentials` property to 'true' if credentials are not required", gw.queryProp("@name"), secretId.str()); + bool omitCredentials = secret.getPropBool("omitCredentials"); + if (isEmptyString(username) && !omitCredentials) + throw makeStringExceptionV(-1, "gateway %s: secret '%s' missing expected 'username' property; set 'omitCredentials` property to 'true' if credentials are not required", gw.queryProp("@name"), secretId.str()); + if (!isEmptyString(username) && omitCredentials) + throw makeStringExceptionV(-1, "gateway %s: secret '%s' contains 'username' and sets 'omitCredentials'", gw.queryProp("@name"), secretId.str()); const char* password = secret.queryProp("password"); if (isEmptyString(username) && password) throw makeStringExceptionV(-1, "gateway %s: '%s' invalid use of password without username", gw.queryProp("@name"), secretId.str()); diff --git a/esp/services/esdl_svc_engine/esdl_binding.hpp b/esp/services/esdl_svc_engine/esdl_binding.hpp index 1c0149d676c..68fdda9ab40 100755 --- a/esp/services/esdl_svc_engine/esdl_binding.hpp +++ b/esp/services/esdl_svc_engine/esdl_binding.hpp @@ -86,7 +86,7 @@ class EsdlServiceImpl : public CInterface, implements IEspService * - Encapsulate non-jsecrets access to support non-standard secret sources, unless * jsecrets is changed to provide this encapsulation. */ - class Secrets + class TransactionSecrets { private: using Key = std::tuple; @@ -142,7 +142,7 @@ class EsdlServiceImpl : public CInterface, implements IEspService */ interface IUpdatableGateway : public IInterface { - virtual IGatewayUpdater* getUpdater(GatewayUpdaters& updaters, Secrets& secrets) const = 0; + virtual IGatewayUpdater* getUpdater(GatewayUpdaters& updaters, TransactionSecrets& secrets) const = 0; }; using UpdatableGateways = std::map>; @@ -157,18 +157,18 @@ class EsdlServiceImpl : public CInterface, implements IEspService * - Insertion (or replacement) of user credentials in a URL string is available to any * subclass that needs it.. * - * All extensions must implement `getUpdater(Secrets&)`. In some cases this may entail creation + * All extensions must implement `getUpdater(TransactionSecrets&)`. In some cases this may entail creation * of a new updater instance. In other cases a single instance may be reused. */ class CUpdatableGateway : public CInterfaceOf { public: - virtual IGatewayUpdater* getUpdater(GatewayUpdaters& updaters, Secrets& secrets) const override; + virtual IGatewayUpdater* getUpdater(GatewayUpdaters& updaters, TransactionSecrets& secrets) const override; protected: std::string updatersKey; protected: CUpdatableGateway(const char* gwName); - virtual IGatewayUpdater* getUpdater(Secrets& secrets) const = 0; + virtual IGatewayUpdater* getUpdater(TransactionSecrets& secrets) const = 0; bool updateURLCredentials(StringBuffer& url, const char* username, const char* password) const; }; @@ -181,11 +181,14 @@ class EsdlServiceImpl : public CInterface, implements IEspService * - If `Gateway/@username` is given, `Gateway/@password` may specify an exncrypted password * value to be decrypted and embedded in an updated URL. * - It is an error to specify `Gateway/@password` without `Gateway/@username`. + * + * Support is provided for backward compatibility. Use of these secrets is strongly discouraged + * and should be avoided whenever possible. */ class CLegacyUrlGateway : public CUpdatableGateway, public IGatewayUpdater { protected: // CUpdatableGateway - virtual CLegacyUrlGateway* getUpdater(Secrets&) const override; + virtual CLegacyUrlGateway* getUpdater(TransactionSecrets&) const override; public: // IGatewayUpdater virtual void updateGateway(IPTree& gw, const char*) override; protected: @@ -203,6 +206,9 @@ class EsdlServiceImpl : public CInterface, implements IEspService * - Defines a standard updater separating dynamically changing secrets from the configuration. * - Enforces a requirement for a local secret to explicitly allow its data to be shared with * a backend roxie service. + * + * Support is provided as an alternative to inline definitions when secret names cannot be + * passed to the target roxie for resolution. Use is discouraged unless it is unavoidable. */ class CLocalSecretGateway : public CUpdatableGateway { @@ -216,15 +222,15 @@ class EsdlServiceImpl : public CInterface, implements IEspService Linked entry; Owned secret; public: - CUpdater(const CLocalSecretGateway& _entry, Secrets& secrets); + CUpdater(const CLocalSecretGateway& _entry, TransactionSecrets& secrets); }; protected: // CUpdatableGateway - virtual IGatewayUpdater* getUpdater(Secrets& secrets) const override; + virtual IGatewayUpdater* getUpdater(TransactionSecrets& secrets) const override; protected: StringBuffer secretId; StringAttr vaultId; StringBuffer secretName; - public: + protected: CLocalSecretGateway(const IPTree& gw, const char* gwName, const char* gwUrl, const char* classPrefix); protected: virtual void doUpdate(IPTree& gw, const IPTree& secret, const char* requiredUsage) const; @@ -241,6 +247,7 @@ class EsdlServiceImpl : public CInterface, implements IEspService * - A secret must define either a non-empty `username` property or set the `omitCredentials` * property to true. * - A secret may define a `password` property if `username` is also defined. + * - A secret must not define `username` and set `omitCredentials` to true. * - A secret must not define a `password` property if `username` is not defined. */ class CHttpConnectGateway : public CLocalSecretGateway @@ -257,12 +264,13 @@ class EsdlServiceImpl : public CInterface, implements IEspService * Gateway updates may occur in either or both of two locations within a backend * service request. The storage layout must enable support for both locations. * - * 1. The optional inclusion of a methods binding definition that does not exclude defined + * 1. The optional inclusion of a method's binding definition that does not exclude defined * gateways, also known as the target context. Target context inclusion must update all * gateways referring to local secrets. Target context inclusion must not, for backward - * compatibility, update any gateways referring to inline URLs. + * compatibility, update any inline gateways unless `Gateways/@updateInline` is true. * 2. The optional request for "legacy gateway transformation". Legacy transformations must - * update all gateways referring to local secrets and inline URLs. + * update all local secret and inline gateways when `Gateways/@legacyTransformTarget` is + * not empty. */ struct GatewaysCacheEntry { @@ -409,29 +417,9 @@ class EsdlServiceImpl : public CInterface, implements IEspService * ESDL script entry point transforms, if any exist. * * Initial request construction of all backend requests wraps the given request content in a - * SOAP envelope and SOAP body. For published requests, where `isroxie` is true, special - * handling for gateways is provided: - * - * - For `Gateways/Gateway` elements found in `tgtctx`: - * - Elements with local secret references are updated to replace `@url` with secret- - * defined data. - * - Elements with inline URL data are updated to insert user credentials into the URL, but - * only if `Gateways/@updateInlineUrls` is true. - * - For `Gateways/Gateway1 elements found in `tgtctx` when `Gateways/@legacyTransformTarget` - * is not empty: - * - Elements with local secret references are updated to replace `@url` with secret- - * defined data. - * - Elements with inline URL data are updated to insert user credentials into the URL. - * - `` becomes - * ``, with `Gateways/@legacyRowName` - * allowing an alternate name for element `row`. - * - The new `gateways` element is placed in the request at the location referred to by - * `Gateways/@legacyTransformTarget`. This XPath supports multiple variable substitutions - * such as: - * - {$query} becomes the value of `Method/@queryname` - * - {$method} becomes the ESDL definition's method name - * - {$service} becomes the ESDL definition's service name - * - {$request} becomes the ESDL definition's method request type + * SOAP envelope and SOAP body. For published requests, where `isroxie` is true, updatable + * gateways are updated prior to inclusion with the `tgtctx` configuration and as part of + * legacy gateway transformations. * * Support for inline URLs in the target configuration, and context which is a subset of the * configuration, is provided for backward compatibility. Use is strongly discouraged. @@ -501,7 +489,7 @@ class EsdlServiceImpl : public CInterface, implements IEspService * @param updaters cache of updaters used in the current transaction * @param secrets cache of secrets used in the current transaction */ - void applyGatewayUpdates(IPTreeIterator& gwIt, const UpdatableGateways& updatables, GatewayUpdaters& updaters, Secrets& secrets) const; + void applyGatewayUpdates(IPTreeIterator& gwIt, const UpdatableGateways& updatables, GatewayUpdaters& updaters, TransactionSecrets& secrets) const; /** * @brief Implementation of legacy gateway transformation invoked only during preparation of