浏览代码

HPCC-22458 Improve ESDL definition auth_feature handling

* Remove the hidlcomp requirement that the ESPservice must include a non-empty
  auth_feature metadata value. The metadata 'auth_feature(" ")' satisfied the
  requirement without adding anything meaningful. Also, the same requirement
  was not enforced for dynamic definitions.
* Define an ESPservice-level metadata value, ping_auth_feature, to define the
  security applied to the generated Ping method. If absent, the security for
  Ping is assumed to be "none".
* Support variable substitution in auth_feature content. Given a service S and
  method M, the metadata "${service}Access:read" yields SAccess:SecAccess_Read,
  while the metadata "${method}Access:full" yields MAccess:SecAccess_Full.
* Apply a default security requirement when no security is explicitly declared.
  The default will be "${service}Access:FULL" when the service is known, and
  "${method}Access:FULL" when it is not.
* Expand the auth_feature grammar to support exclusions. If each auth_feature
  value is considered to be a list of tokens, and a level of precedence is
  assigned to each token from each list, exclusion tokens can ignore any or
  all tokens with lower precedence based on either the origin of the token or
  the feature name it references.
* Extend the esdl command line interface to recognize option "-tcat"/
  "--trace-category". The supported category values are derived from jlog, and
  are described in the tool's usage. This change enables a tester to evaluate
  how the security in a dynamic definition is handled when publishing.

This PR is a continuation of PR #12874. A failed rebase caused most of the
changes in that PR to be discarded. This PR includes only the discarded changes.

Signed-off-by: Tim Klemm <tim.klemm@lexisnexisrisk.com>
Tim Klemm 5 年之前
父节点
当前提交
ea6c16b5bb

+ 1 - 0
esp/esdllib/CMakeLists.txt

@@ -29,6 +29,7 @@ include_directories (
     ${HPCC_SOURCE_DIR}/rtl/eclrtl
     ${HPCC_SOURCE_DIR}/rtl/include #IXMLWriter
     ${HPCC_SOURCE_DIR}/common/thorhelper #JSONWRITER
+    ${HPCC_SOURCE_DIR}/tools/hidl #TAccessMapGenerator
 )
 
 ADD_DEFINITIONS ( -D_USRDLL -DESDLLIB_EXPORTS )

+ 153 - 0
esp/esdllib/EsdlAccessMapGenerator.hpp

@@ -0,0 +1,153 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    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.
+############################################################################## */
+
+#ifndef _EsdlAccessMapGenerator_HPP_
+#define _EsdlAccessMapGenerator_HPP_
+
+#include "AccessMapGenerator.hpp"
+#include "esdl_def.hpp"
+#include "espcontext.hpp"
+#include "jlog.hpp"
+#include "jscm.hpp"
+#include "seclib.hpp"
+
+using EsdlAccessMapGenerator = TAccessMapGenerator<SecAccessFlags>;
+using EsdlAccessMapScopeMapper = EsdlAccessMapGenerator::ScopeMapper;
+
+struct EsdlAccessMapLevelMapper : public EsdlAccessMapGenerator::LevelMapper
+{
+    SecAccessFlags levelUnavailable() const override { return SecAccess_Unavailable; }
+    SecAccessFlags levelNone() const override { return SecAccess_None; }
+    SecAccessFlags levelDeferred() const override { return SecAccess_None; }
+    SecAccessFlags levelAccess() const override { return SecAccess_Access; }
+    SecAccessFlags levelRead() const override { return SecAccess_Read; }
+    SecAccessFlags levelWrite() const override { return SecAccess_Write; }
+    SecAccessFlags levelFull() const override { return SecAccess_Full; }
+    SecAccessFlags levelUnknown() const override { return SecAccess_Unknown; }
+
+    bool isEqual(SecAccessFlags lhs, SecAccessFlags rhs) const override
+    {
+        return lhs == rhs;
+    }
+
+    const char* toString(SecAccessFlags level) const override
+    {
+#define SECACCESSFLAGS_CASE(flag) case flag: return #flag
+    switch (level)
+    {
+    SECACCESSFLAGS_CASE(SecAccess_Unavailable);
+    SECACCESSFLAGS_CASE(SecAccess_None);
+    SECACCESSFLAGS_CASE(SecAccess_Access);
+    SECACCESSFLAGS_CASE(SecAccess_Read);
+    SECACCESSFLAGS_CASE(SecAccess_Write);
+    SECACCESSFLAGS_CASE(SecAccess_Full);
+    default:
+    SECACCESSFLAGS_CASE(SecAccess_Unknown);
+    }
+#undef SECACCESSFLAGS_CASE
+    }
+};
+
+struct EsdlAccessMapReporter : public EsdlAccessMapGenerator::Reporter
+{
+    MapStringTo<SecAccessFlags>& m_accessMap;
+    Owned<IEsdlDefReporter>      m_reporter;
+
+    EsdlAccessMapReporter(MapStringTo<SecAccessFlags>& accessMap, IEsdlDefReporter* reporter)
+        : m_accessMap(accessMap)
+    {
+        setEsdlReporter(reporter);
+    }
+
+    void setEsdlReporter(IEsdlDefReporter* reporter)
+    {
+        m_reporter.setown(reporter);
+    }
+
+    bool errorsAreFatal() const override
+    {
+        return true;
+    }
+
+    bool reportError() const override
+    {
+        return reportType(IEsdlDefReporter::ReportUError);
+    }
+
+    bool reportWarning() const override
+    {
+        return reportType(IEsdlDefReporter::ReportUWarning);
+    }
+
+    bool reportInfo() const override
+    {
+        return reportType(IEsdlDefReporter::ReportUInfo);
+    }
+
+    bool reportDebug() const override
+    {
+        return reportType(IEsdlDefReporter::ReportDInfo);
+    }
+
+    void entry(const char* name, SecAccessFlags level) const override
+    {
+        m_accessMap.setValue(name, level);
+    }
+
+protected:
+#define REPORT_FLAGS(f) (f | IEsdlDefReporter::ReportMethod)
+    void reportError(const char* fmt, va_list& args) const override
+    {
+        StringBuffer msg;
+        msg.valist_appendf(fmt, args);
+
+        // The exception is thrown first due to a crash in the esdl application when the
+        // exception occurs while fprintf is processing the message.
+        if (errorsAreFatal())
+            throw MakeStringException(0, "%s", msg.str());
+        if (m_reporter.get() != nullptr)
+            m_reporter->report(REPORT_FLAGS(IEsdlDefReporter::ReportUError), fmt, args);
+    }
+
+    void reportWarning(const char* fmt, va_list& args) const override
+    {
+        if (m_reporter.get() != nullptr)
+            m_reporter->report(REPORT_FLAGS(IEsdlDefReporter::ReportUWarning), fmt, args);
+    }
+
+    void reportInfo(const char* fmt, va_list& args) const override
+    {
+        if (m_reporter.get() != nullptr)
+            m_reporter->report(REPORT_FLAGS(IEsdlDefReporter::ReportUInfo), fmt, args);
+    }
+
+    void reportDebug(const char* fmt, va_list& args) const override
+    {
+        if (m_reporter.get() != nullptr)
+            m_reporter->report(REPORT_FLAGS(IEsdlDefReporter::ReportDInfo), fmt, args);
+    }
+
+    bool reportType(IEsdlDefReporter::Flags flag) const
+    {
+        if (m_reporter.get() != nullptr)
+            return m_reporter->testFlags(REPORT_FLAGS(flag));
+        return false;
+    }
+#undef REPORT_FLAGS
+};
+
+#endif // _EsdlAccessMapGenerator_HPP_

+ 57 - 98
esp/esdllib/esdl_def.cpp

@@ -20,6 +20,7 @@
 #include "jliball.hpp"
 #include "espcontext.hpp"
 #include "esdl_def.hpp"
+#include "EsdlAccessMapGenerator.hpp"
 #include <xpp/XmlPullParser.h>
 #include <memory>
 
@@ -961,69 +962,6 @@ void EsdlDefStruct::load(EsdlDefinition *esdl, XmlPullParser *xpp, StartTag &str
     }
 }
 
-static SecAccessFlags translateAuthLevel(const char* flag)
-{
-    if (!flag || !*flag)
-        return SecAccess_Full;
-    if (!stricmp(flag,"None") || !stricmp(flag,"Deferred"))
-        return SecAccess_None;
-    if (!stricmp(flag,"Access"))
-        return SecAccess_Access;
-    if (!stricmp(flag,"Read"))
-        return SecAccess_Read;
-    if (!stricmp(flag,"Write"))
-        return SecAccess_Write;
-    if (!stricmp(flag,"Full"))
-        return SecAccess_Full;
-
-    DBGLOG("Unknown access level: %s", flag);
-    throw( MakeStringException(0, "Unknown access level: %s", flag) );
-}
-
-static void parseAccessList(const char * rawServiceAccessList, MapStringTo<SecAccessFlags> & accessmap, const char * defaultaccessname)
-{
-    if (rawServiceAccessList && *rawServiceAccessList)
-    {
-        StringBuffer currAccessName;
-        StringBuffer currAccessLevel;
-
-        StringArray accessList;
-        accessList.appendList(rawServiceAccessList, ",");
-        ForEachItemIn(idx, accessList)
-        {
-            currAccessName.clear();
-            currAccessLevel.clear();
-            const char * accessEntry = accessList.item(idx);
-            int entrylen = strlen(accessEntry);
-            int currIndex = 0;
-
-            for (;currIndex <= entrylen && accessEntry[currIndex] != ':'; currIndex++ )
-            {
-                if (!isspace(accessEntry[currIndex]))
-                    currAccessName.append(accessEntry[currIndex]);
-            }
-
-            if (accessEntry[currIndex] == ':')
-            {
-                currIndex++;
-                if (currAccessName.isEmpty())
-                    currAccessName.setf("%sAccess",  defaultaccessname);
-            }
-
-            for (;currIndex <= entrylen; currIndex++ )
-            {
-                if (!isspace(accessEntry[currIndex]))
-                    currAccessLevel.append(accessEntry[currIndex]);
-            }
-
-            if (strieq(currAccessName, "NONE") || strieq(currAccessName, "DEFERRED"))
-                continue;
-
-            accessmap.setValue(currAccessName.str(), translateAuthLevel(currAccessLevel.str()));
-        }
-    }
-}
-
 class EsdlDefMethod : public EsdlDefObject, implements IEsdlDefMethod
 {
 public:
@@ -1033,35 +971,7 @@ public:
     MapStringTo<SecAccessFlags> m_accessmap;
     const MapStringTo<SecAccessFlags> & queryAccessMap(){return m_accessmap;}
 
-    EsdlDefMethod(StartTag &tag, EsdlDefinition *esdl, IEsdlDefService * parentservice = nullptr) : EsdlDefObject(tag, esdl)
-    {
-        const char *product = queryProp("productAssociation");
-        if (product && *product)
-        {
-            if (strstr(product, ":default"))
-            {
-                StringBuffer val;
-                const char * finger = product;
-                while(*finger && *finger !=':'){val.append(*finger++);}
-
-                props->setProp("product_", val.str());
-                props->setProp("productdefault_", true);
-            }
-            else
-                props->setProp("product_", product);
-        }
-
-        StringBuffer allfeatures;
-        if (parentservice)
-        {
-            allfeatures.set(parentservice->queryProp("auth_feature"));
-            if (!allfeatures.isEmpty())
-                allfeatures.append(',');
-        }
-
-        allfeatures.append(queryMetaData("auth_feature"));
-        parseAccessList(allfeatures.str(), m_accessmap, parentservice ? parentservice->queryName() :  queryProp("name"));
-    }
+    EsdlDefMethod(StartTag &tag, EsdlDefinition *esdl, IEsdlDefService * parentservice = nullptr);
 
     virtual EsdlDefTypeId getEsdlType(){return EsdlTypeMethod;}
 
@@ -1369,13 +1279,17 @@ public:
 
     Owned<IPropertyTree> flConfig;
 
+    Owned<IEsdlDefReporter> reporter;
+
 public:
     IMPLEMENT_IINTERFACE;
 
-    EsdlDefinition()
+    EsdlDefinition(EsdlDefReporterFactory factory)
     {
         verdefs.setown(createProperties(true));
         optionals.setown(createProperties(true));
+        if (factory)
+            setReporter(factory());
     }
 
     ~EsdlDefinition()
@@ -1402,6 +1316,14 @@ public:
         }
     }
 
+    void setReporter(IEsdlDefReporter* _reporter) override
+    {
+        reporter.setown(_reporter);
+    }
+    IEsdlDefReporter* queryReporter() const override
+    {
+        return reporter.get();
+    }
     void addDefinitionFromXML(const StringBuffer & xmlDef, const char * esdlDefName, double ver);
     void addDefinitionFromXML(const StringBuffer & xmlDef, const char * esdlDefId);
     void addDefinitionsFromFile(const char *filename);
@@ -2157,6 +2079,43 @@ EsdlDefObject::EsdlDefObject(StartTag &tag, EsdlDefinition *esdl)
     }
 }
 
+EsdlDefMethod::EsdlDefMethod(StartTag &tag, EsdlDefinition *esdl, IEsdlDefService * parentservice) : EsdlDefObject(tag, esdl)
+{
+    const char *product = queryProp("productAssociation");
+    if (product && *product)
+    {
+        if (strstr(product, ":default"))
+        {
+            StringBuffer val;
+            const char * finger = product;
+            while(*finger && *finger !=':'){val.append(*finger++);}
+
+            props->setProp("product_", val.str());
+            props->setProp("productdefault_", true);
+        }
+        else
+            props->setProp("product_", product);
+    }
+
+    EsdlAccessMapScopeMapper scopeMapper({"EsdlService", "EsdlMethod"});
+    EsdlAccessMapLevelMapper levelMapper;
+    EsdlAccessMapReporter    reporter(m_accessmap, LINK(esdl->queryReporter()));
+    EsdlAccessMapGenerator   generator(scopeMapper, levelMapper, reporter);
+
+    generator.setVariable("method", queryProp("name"));
+    generator.insertScope("EsdlMethod", queryMetaData("auth_feature"));
+    if (parentservice)
+    {
+        generator.setVariable("service", parentservice->queryName());
+        generator.insertScope("EsdlService", parentservice->queryProp("auth_feature"));
+        generator.setDefaultSecurity("${service}Access:FULL");
+    }
+    else
+    {
+        generator.setDefaultSecurity("${method}Access:FULL");
+    }
+    generator.generateMap();
+}
 
 static Owned<IEsdlDefinition> default_ns;
 
@@ -2166,14 +2125,14 @@ typedef MapStringTo<IEsdlDefinitionPtr> EsdlNamespaceMap;
 
 EsdlNamespaceMap esdl_namespaces;
 
-esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns)
+esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns, EsdlDefReporterFactory factory)
 {
     if (esdl_ns && *esdl_ns)
     {
         IEsdlDefinition **ptns = esdl_namespaces.getValue(esdl_ns);
         if (!ptns)
         {
-            IEsdlDefinition *tns = new EsdlDefinition();
+            IEsdlDefinition *tns = new EsdlDefinition(factory);
             esdl_namespaces.setValue(esdl_ns, tns);
             return LINK<IEsdlDefinition>(tns);
         }
@@ -2181,16 +2140,16 @@ esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns)
             return LINK<IEsdlDefinition>(*ptns);
     }
     else if (!default_ns)
-        default_ns.setown(new EsdlDefinition());
+        default_ns.setown(new EsdlDefinition(factory));
     return default_ns.getLink();
 }
 
-esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns)
+esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns, EsdlDefReporterFactory factory)
 {
     if (esdl_ns && *esdl_ns)
         return createEsdlDefinition(esdl_ns);
     else
-        return new EsdlDefinition();
+        return new EsdlDefinition(factory);
 }
 
 esdl_decl IEsdlDefinition *queryEsdlDefinition(const char *esdl_ns)

+ 151 - 2
esp/esdllib/esdl_def.hpp

@@ -188,8 +188,11 @@ interface IEsdlDefFileIterator : extends IIteratorOf<IEsdlDefFile>
 {
 };
 
+interface IEsdlDefReporter;
 interface IEsdlDefinition : extends IInterface
 {
+    virtual void setReporter(IEsdlDefReporter* reporter)=0;
+    virtual IEsdlDefReporter* queryReporter() const=0;
     virtual void addDefinitionsFromFile(const char *filename)=0;
     virtual void addDefinitionFromXML(const StringBuffer & xmlDef, const char * esdlDefName, double ver)=0;
     virtual void addDefinitionFromXML(const StringBuffer & xmlDef, const char * esdlDefId)=0;
@@ -222,12 +225,158 @@ interface IEsdlDefinition : extends IInterface
     virtual bool isShared() = 0;
 };
 
-esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns=NULL);
-esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns=NULL);
+typedef IEsdlDefReporter* (*EsdlDefReporterFactory)();
+esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns=NULL, EsdlDefReporterFactory factory = nullptr);
+esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns=nullptr, EsdlDefReporterFactory factory = nullptr);
 esdl_decl IEsdlDefinition *queryEsdlDefinition(const char *esdl_ns=NULL);
 esdl_decl void releaseEsdlDefinition(const char *esdl_ns=NULL);
 
 esdl_decl void initEsdlTypeList();
 esdl_decl EsdlBasicElementType esdlSimpleType(const char *type);
 
+interface IEsdlDefReporter : extends IInterface
+{
+    using Flags = uint64_t;
+    static const Flags ReportDisaster  = 1 << 0;
+    static const Flags ReportAError    = 1 << 1;
+    static const Flags ReportIError    = 1 << 2;
+    static const Flags ReportOError    = 1 << 3;
+    static const Flags ReportUError    = 1 << 4;
+    static const Flags ReportIWarning  = 1 << 5;
+    static const Flags ReportOWarning  = 1 << 6;
+    static const Flags ReportUWarning  = 1 << 7;
+    static const Flags ReportDProgress = 1 << 8;
+    static const Flags ReportOProgress = 1 << 9;
+    static const Flags ReportUProgress = 1 << 10;
+    static const Flags ReportDInfo     = 1 << 11;
+    static const Flags ReportOInfo     = 1 << 12;
+    static const Flags ReportUInfo     = 1 << 13;
+    static const Flags ReportStats     = 1 << 14;
+    static const Flags ReportCategoryMask =
+            ReportDisaster |
+            ReportAError | ReportIError | ReportOError | ReportUError |
+            ReportIWarning | ReportOWarning | ReportUWarning |
+            ReportDProgress | ReportOProgress | ReportUProgress |
+            ReportDInfo | ReportOInfo | ReportUInfo |
+            ReportStats;
+    static const Flags ReportErrorClass = ReportIError | ReportOError | ReportUError;
+    static const Flags ReportWarningClass = ReportIWarning | ReportOWarning | ReportUWarning;
+    static const Flags ReportProgressClass = ReportDProgress | ReportOProgress | ReportUProgress;
+    static const Flags ReportInfoClass = ReportDInfo | ReportOInfo | ReportUInfo;
+    static const Flags ReportDeveloperAudience = ReportIError | ReportIWarning | ReportDProgress | ReportDInfo;
+    static const Flags ReportOperatorAudience = ReportOError | ReportOWarning | ReportOProgress | ReportOInfo;
+    static const Flags ReportUserAudience = ReportUError | ReportUWarning | ReportUProgress | ReportUInfo;
+
+    static const Flags ReportDefinition = Flags(1) << 63;
+    static const Flags ReportService    = Flags(1) << 62;
+    static const Flags ReportMethod     = Flags(1) << 61;
+    static const Flags ReportComponentMask = Flags(UINT64_MAX) & ~ReportCategoryMask;
+
+    virtual Flags queryFlags() const = 0;
+    virtual Flags getFlags(Flags mask = Flags(-1)) const = 0;
+    virtual bool testFlags(Flags flags) const = 0;
+    virtual void setFlags(Flags flags, bool state) = 0;
+    virtual void report(Flags flags, const char* fmt, ...) const = 0;
+    virtual void report(Flags flags, const char* fmt, va_list& args) const = 0;
+    virtual void report(Flags flags, const StringBuffer& msg) const = 0;
+};
+
+class EsdlDefReporter : public IEsdlDefReporter, public CInterface
+{
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Flags queryFlags() const override { return m_flags; }
+    Flags getFlags(Flags mask) const override { return m_flags & mask; }
+    bool  testFlags(Flags flags) const override { return (m_flags & flags) == flags; }
+
+    void  setFlags(Flags flags, bool state) override
+    {
+        if (state)
+            m_flags = m_flags | flags;
+        else
+            m_flags = m_flags & ~flags;
+    }
+
+    void report(Flags flags, const char* fmt, ...) const
+    {
+        if (testFlags(flags))
+        {
+            va_list args;
+            va_start(args, fmt);
+            reportSelf(flags, fmt, args);
+            va_end(args);
+        }
+    }
+
+    void report(Flags flags, const char* fmt, va_list& args) const
+    {
+        if (testFlags(flags))
+            reportSelf(flags, fmt, args);
+    }
+
+    void report(Flags flags, const StringBuffer& msg) const
+    {
+        if (testFlags(flags))
+            reportSelf(flags, msg);
+    }
+
+protected:
+    void reportSelf(Flags flags, const char* fmt, va_list& args) const
+    {
+        StringBuffer msg;
+        msg.valist_appendf(fmt, args);
+        reportSelf(flags, msg);
+    }
+
+    virtual void reportSelf(Flags flags, const StringBuffer& msg) const
+    {
+        Flags masked = getFlags(flags);
+        const char* componentLabel = getComponentLabel(flags);
+        const char* levelLabel = getLevelLabel(flags);
+
+        if (componentLabel != nullptr && levelLabel != nullptr)
+            reportSelf(flags, componentLabel, levelLabel, msg);
+    }
+
+    const char* getComponentLabel(Flags flags) const
+    {
+        switch (getFlags(ReportComponentMask))
+        {
+        case ReportDefinition: return "EsdlDefinition";
+        case ReportService: return "EsdlDefService";
+        case ReportMethod: return "EsdlDefMethod";
+        default: return nullptr;
+        }
+    }
+
+    const char* getLevelLabel(Flags flags) const
+    {
+        switch (flags & getFlags(ReportCategoryMask))
+        {
+        case ReportDisaster : return "Disaster";
+        case ReportAError : return "Audit Error";
+        case ReportIError: return "Internal Error";
+        case ReportOError: return "Operator Error";
+        case ReportUError: return "User Error";
+        case ReportIWarning: return "Internal Warning";
+        case ReportOWarning: return "Operator Warning";
+        case ReportUWarning: return "User Warning";
+        case ReportDProgress: return "Debug Progress";
+        case ReportOProgress: return "Operator Progress";
+        case ReportUProgress: return "User Progress";
+        case ReportDInfo: return "Debug Info";
+        case ReportOInfo: return "Operator Info";
+        case ReportUInfo: return "User Info";
+        case ReportStats: return "Stats";
+        default: return nullptr;
+        }
+    }
+
+    virtual void reportSelf(Flags flags, const char* component, const char* level, const char* msg) const = 0;
+
+private:
+    Flags m_flags = 0;
+};
+
 #endif //ESDLDEF_HPP

+ 2 - 2
tools/esdlcmd/esdl-publish.cpp

@@ -122,7 +122,7 @@ public:
         Owned<IClientPublishESDLDefinitionRequest> request = esdlConfigClient->createPublishESDLDefinitionRequest();
 
         StringBuffer esxml;
-        esdlHelper->getServiceESXDL(optSource.get(), optESDLService.get(), esxml, 0, NULL, (DEPFLAG_INCLUDE_TYPES & ~DEPFLAG_INCLUDE_METHOD), optIncludePath.str());
+        esdlHelper->getServiceESXDL(optSource.get(), optESDLService.get(), esxml, 0, NULL, (DEPFLAG_INCLUDE_TYPES & ~DEPFLAG_INCLUDE_METHOD), optIncludePath.str(), optTraceFlags());
         if (esxml.length()==0)
         {
             fprintf(stderr,"\nESDL Definition for service %s could not be loaded from: %s\n", optESDLService.get(), optSource.get());
@@ -1254,7 +1254,7 @@ public:
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientGetESDLBindingRequest> getrequest = esdlConfigClient->createGetESDLBindingRequest();
         if (optVerbose)
-            fprintf(stdout,"\nFetching current ESDL binging configuration for (%s)\n", optBindingId.get());
+            fprintf(stdout,"\nFetching current ESDL binding configuration for (%s)\n", optBindingId.get());
         getrequest->setEsdlBindingId(optBindingId.get());
 
         Owned<IClientGetESDLBindingResponse> getresp = esdlConfigClient->GetESDLBinding(getrequest);

+ 52 - 0
tools/esdlcmd/esdlcmd_common.cpp

@@ -91,6 +91,13 @@ esdlCmdOptionMatchIndicator EsdlCmdCommon::matchCommandLineOption(ArgvIterator &
         return EsdlCmdOptionMatch;
     }
 
+    StringAttr traceCategories;
+    if (iter.matchOption(traceCategories, ESDL_OPTION_TRACE_CATEGORY) || iter.matchOption(traceCategories, ESDL_OPT_TRACE_CATEGORY))
+    {
+        parseTraceFlags(traceCategories);
+        return EsdlCmdOptionMatch;
+    }
+
     StringAttr tempArg;
     if (iter.matchOption(tempArg, "-brk"))
     {
@@ -111,6 +118,51 @@ esdlCmdOptionMatchIndicator EsdlCmdCommon::matchCommandLineOption(ArgvIterator &
     return EsdlCmdOptionNoMatch;
 }
 
+void EsdlCmdCommon::parseTraceFlags(const char* traceCategories)
+{
+    m_optTraceFlagsGiven = true;
+    if (!isEmptyString(traceCategories))
+    {
+        using Category = std::pair<const char*, IEsdlDefReporter::Flags>;
+        using CategoryMap = std::list<Category>;
+        static const CategoryMap definedCategories({
+            { ESDL_TRACE_CATEGORY_DEVELOPER, IEsdlDefReporter::ReportDeveloperAudience },
+            { ESDL_TRACE_CATEGORY_OPERATOR, IEsdlDefReporter::ReportOperatorAudience },
+            { ESDL_TRACE_CATEGORY_USER, IEsdlDefReporter::ReportUserAudience },
+            { ESDL_TRACE_CATEGORY_ERROR, IEsdlDefReporter::ReportErrorClass },
+            { ESDL_TRACE_CATEGORY_WARNING, IEsdlDefReporter::ReportWarningClass },
+            { ESDL_TRACE_CATEGORY_PROGRESS, IEsdlDefReporter::ReportProgressClass },
+            { ESDL_TRACE_CATEGORY_INFO, IEsdlDefReporter::ReportInfoClass },
+            { ESDL_TRACE_CATEGORY_IERROR, IEsdlDefReporter::ReportIError },
+            { ESDL_TRACE_CATEGORY_OERROR, IEsdlDefReporter::ReportOError },
+            { ESDL_TRACE_CATEGORY_UERROR, IEsdlDefReporter::ReportUError },
+            { ESDL_TRACE_CATEGORY_IWARNING, IEsdlDefReporter::ReportIWarning },
+            { ESDL_TRACE_CATEGORY_OWARNING, IEsdlDefReporter::ReportOWarning },
+            { ESDL_TRACE_CATEGORY_UWARNING, IEsdlDefReporter::ReportUWarning },
+            { ESDL_TRACE_CATEGORY_DPROGRESS, IEsdlDefReporter::ReportDProgress },
+            { ESDL_TRACE_CATEGORY_OPROGRESS, IEsdlDefReporter::ReportOProgress },
+            { ESDL_TRACE_CATEGORY_UPROGRESS, IEsdlDefReporter::ReportUProgress },
+            { ESDL_TRACE_CATEGORY_DINFO, IEsdlDefReporter::ReportDInfo },
+            { ESDL_TRACE_CATEGORY_OINFO, IEsdlDefReporter::ReportOInfo },
+            { ESDL_TRACE_CATEGORY_UINFO, IEsdlDefReporter::ReportUInfo },
+        });
+        StringArray categories;
+        categories.appendList(traceCategories, ",");
+        for (aindex_t idx = 0; idx < categories.ordinality(); idx++) // not using ForEachItemIn because ordinality may change
+        {
+            const char* category = categories.item(idx);
+            CategoryMap::const_iterator it = std::find_if(definedCategories.begin(), definedCategories.end(), [category](const Category& entry) {
+                return strieq(category, entry.first);
+            });
+
+            if (it != definedCategories.end())
+            {
+                m_actualTraceFlags |= it->second;
+            }
+        }
+    }
+}
+
 bool EsdlCmdCommon::finalizeOptions(IProperties *globals)
 {
     if (!optVerbose)

+ 65 - 6
tools/esdlcmd/esdlcmd_common.hpp

@@ -27,6 +27,9 @@
 #include "ws_esdlconfig_esp.ipp"
 #include "esdl2xml.hpp"
 
+#include <algorithm>
+#include <list>
+
 #define COMPONENTS_DIR_NAME "componentfiles"
 #define HIGHER_DIR_RELATIVE ".."
 
@@ -49,6 +52,28 @@ typedef IEsdlCommand *(*EsdlCommandFactory)(const char *cmdname);
 #define ESDL_OPTION_VERBOSE              "--verbose"
 #define ESDL_OPT_VERBOSE                 "-v"
 
+#define ESDL_OPTION_TRACE_CATEGORY      "--trace-category"
+#define ESDL_OPT_TRACE_CATEGORY         "-tcat"
+#define ESDL_TRACE_CATEGORY_IERROR      "ie"
+#define ESDL_TRACE_CATEGORY_OERROR      "oe"
+#define ESDL_TRACE_CATEGORY_UERROR      "ue"
+#define ESDL_TRACE_CATEGORY_IWARNING    "iw"
+#define ESDL_TRACE_CATEGORY_OWARNING    "ow"
+#define ESDL_TRACE_CATEGORY_UWARNING    "uw"
+#define ESDL_TRACE_CATEGORY_DPROGRESS   "dp"
+#define ESDL_TRACE_CATEGORY_OPROGRESS   "op"
+#define ESDL_TRACE_CATEGORY_UPROGRESS   "up"
+#define ESDL_TRACE_CATEGORY_DINFO       "di"
+#define ESDL_TRACE_CATEGORY_OINFO       "oi"
+#define ESDL_TRACE_CATEGORY_UINFO       "ui"
+#define ESDL_TRACE_CATEGORY_DEVELOPER   "dev"
+#define ESDL_TRACE_CATEGORY_OPERATOR    "admin"
+#define ESDL_TRACE_CATEGORY_USER        "user"
+#define ESDL_TRACE_CATEGORY_ERROR       "err"
+#define ESDL_TRACE_CATEGORY_WARNING     "warn"
+#define ESDL_TRACE_CATEGORY_PROGRESS    "prog"
+#define ESDL_TRACE_CATEGORY_INFO        "info"
+
 #define ESDL_CONVERT_SOURCE             "--source"
 #define ESDL_CONVERT_OUTDIR             "--outdir"
 
@@ -78,7 +103,6 @@ typedef IEsdlCommand *(*EsdlCommandFactory)(const char *cmdname);
 #define ESDLOPT_NO_ARRAYOF              "--no-arrayof"
 #define ESDLOPT_OUTPUT_CATEGORIES       "--output-categories"
 #define ESDLOPT_USE_UTF8_STRINGS        "--utf8"
-
 #define ESDLOPT_NO_EXPORT               "--no-export"
 #define ESDLOPT_HIDE_GETDATAFROM        "--hide-get-data-from"
 #define ESDLOPT_WSDL_ADDRESS            "--wsdl-address"
@@ -114,6 +138,7 @@ typedef IEsdlCommand *(*EsdlCommandFactory)(const char *cmdname);
 #define ESDLOPT_INCLUDE_PATH_ENV        "ESDL_INCLUDE_PATH"
 #define ESDLOPT_INCLUDE_PATH_INI        "esdlIncludePath"
 #define ESDLOPT_INCLUDE_PATH_USAGE      "   -I, --include-path <include path>    Locations to look for included esdl files\n"
+
 bool matchVariableOption(ArgvIterator &iter, const char prefix, IArrayOf<IEspNamedValue> &values);
 
 enum esdlCmdOptionMatchIndicator
@@ -123,9 +148,22 @@ enum esdlCmdOptionMatchIndicator
     EsdlCmdOptionCompletion=2
 };
 
+class EsdlCmdReporter : public EsdlDefReporter
+{
+protected:
+    void reportSelf(Flags flag, const char* component, const char* level, const char* msg) const override
+    {
+        fprintf(stdout, "%s [%s]: %s\n", level, component, msg);
+    }
+};
+
 class EsdlCmdCommon : public CInterface, implements IEsdlCommand
 {
 public:
+    using TraceFlags = IEsdlDefReporter::Flags;
+    static const TraceFlags defaultSuccinctTraceFlags = IEsdlDefReporter::ReportErrorClass | IEsdlDefReporter::ReportWarningClass;
+    static const TraceFlags defaultVerboseTraceFlags = defaultSuccinctTraceFlags | IEsdlDefReporter::ReportProgressClass | IEsdlDefReporter::ReportInfoClass;
+
     IMPLEMENT_IINTERFACE;
     EsdlCmdCommon() : optVerbose(false)
     {}
@@ -137,6 +175,16 @@ public:
         fprintf(stdout,
             "   --help                               Display usage information for the given command\n"
             "   -v,--verbose                         Output additional tracing information\n"
+            "   -tcat,--trace-category <flags>       Control which debug messages are output; a case-insensitive comma-delimited combination of:\n"
+            "                                            " ESDL_TRACE_CATEGORY_DEVELOPER ": all output for the developer audience\n"
+            "                                            " ESDL_TRACE_CATEGORY_OPERATOR ": all output for the operator audience\n"
+            "                                            " ESDL_TRACE_CATEGORY_USER ": all output for the user audience\n"
+            "                                            " ESDL_TRACE_CATEGORY_ERROR ": all error output\n"
+            "                                            " ESDL_TRACE_CATEGORY_WARNING ": all warning output\n"
+            "                                            " ESDL_TRACE_CATEGORY_PROGRESS ": all progress output\n"
+            "                                            " ESDL_TRACE_CATEGORY_INFO ": all info output\n"
+            "                                        Errors and warnings are enabled by default if not verbose, and all are enabled when verbose."
+            "                                        Use an empty <flags> value to disable all."
         );
     }
     virtual void outputWsStatus(int code, const char * message)
@@ -144,11 +192,20 @@ public:
         fprintf(code == 0 ? stdout : stderr, "\n %s.\n", message);
     }
 public:
+    inline TraceFlags optTraceFlags() { return (m_optTraceFlagsGiven ? m_actualTraceFlags : (optVerbose ? m_verboseTraceFlags : m_succinctTraceFlags)) | IEsdlDefReporter::ReportMethod; }
     bool optVerbose;
+protected:
+    void parseTraceFlags(const char* traceCategories);
+    TraceFlags m_succinctTraceFlags = defaultSuccinctTraceFlags;
+    TraceFlags m_verboseTraceFlags = defaultVerboseTraceFlags;
+private:
+    TraceFlags m_actualTraceFlags = 0;
+    bool m_optTraceFlagsGiven = false;
 };
 
 class EsdlCmdHelper : public CInterface
 {
+    static IEsdlDefReporter* makeCmdReporter() { return new EsdlCmdReporter(); }
 public:
     Owned<IEsdlDefinition> esdlDef;
     Owned<IEsdlDefinitionHelper> defHelper;
@@ -158,7 +215,7 @@ public:
 public:
     EsdlCmdHelper()
     {
-        esdlDef.set(createEsdlDefinition());
+        esdlDef.set(createEsdlDefinition(nullptr, makeCmdReporter));
         defHelper.set(createEsdlDefinitionHelper());
     }
 
@@ -169,10 +226,12 @@ public:
         return new EsdlCmdHelper();
     }
 
-    void loadDefinition(const char * sourceFileName, const char * serviceName, double version, const char* includePath)
+    void loadDefinition(const char * sourceFileName, const char * serviceName, double version, const char* includePath, IEsdlDefReporter::Flags traceFlags)
     {
         if (!esdlDef.get())
-            esdlDef.set(createEsdlDefinition());
+            esdlDef.set(createEsdlDefinition(nullptr, makeCmdReporter));
+        IEsdlDefReporter* reporter = esdlDef->queryReporter();
+        reporter->setFlags(traceFlags, true);
 
         if(!esdlDef->hasFileLoaded(sourceFileName))
         {
@@ -192,9 +251,9 @@ public:
         }
     }
 
-    void getServiceESXDL(const char * sourceFileName, const char * serviceName, StringBuffer & xmlOut, double version, IProperties *opts=NULL, unsigned flags=0, const char* includePath=NULL)
+    void getServiceESXDL(const char * sourceFileName, const char * serviceName, StringBuffer & xmlOut, double version, IProperties *opts=nullptr, unsigned flags=0, const char* includePath=nullptr, IEsdlDefReporter::Flags traceFlags = EsdlCmdCommon::defaultSuccinctTraceFlags)
     {
-        loadDefinition(sourceFileName, serviceName, version, includePath);
+        loadDefinition(sourceFileName, serviceName, version, includePath, traceFlags);
 
         if (esdlDef)
         {

+ 4 - 4
tools/esdlcmd/esdlcmd_core.cpp

@@ -216,7 +216,7 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService.get(), optInterfaceVersion,"");
+        cmdHelper.loadDefinition(optSource, optService.get(), optInterfaceVersion,"", optTraceFlags());
         createOptionals();
 
         Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optInterfaceVersion, opts.get(), optFlags );
@@ -503,7 +503,7 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService.get(), optInterfaceVersion, "");
+        cmdHelper.loadDefinition(optSource, optService.get(), optInterfaceVersion, "", optTraceFlags());
         createOptionals();
 
         Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optInterfaceVersion, opts.get(), optFlags );
@@ -696,7 +696,7 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath);
+        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath, optTraceFlags());
         Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, 0, NULL, optFlags );
 
         if(!optPreprocessOutputDir.isEmpty())
@@ -928,7 +928,7 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath);
+        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath, optTraceFlags());
         Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, 0, NULL, optFlags );
 
         if(!optPreprocessOutputDir.isEmpty())

+ 2 - 2
tools/esdlcmd/esdlcmd_monitor.cpp

@@ -294,7 +294,7 @@ public:
 
     virtual void loadServiceDef()
     {
-        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath);
+        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath, optTraceFlags());
     }
 
 public:
@@ -984,7 +984,7 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath);
+        cmdHelper.loadDefinition(optSource, optService, 0, optIncludePath, optTraceFlags());
 
         Owned<IEsdlDefObjectIterator> responseEsdl = cmdHelper.esdlDef->getDependencies(optService, optMethod, 0, nullptr, DEPFLAG_INCLUDE_RESPONSE | DEPFLAG_INCLUDE_METHOD | DEPFLAG_ECL_ONLY);
         Owned<IEsdlDefObjectIterator> requestEsdl = cmdHelper.esdlDef->getDependencies(optService, optMethod, 0, nullptr, DEPFLAG_INCLUDE_REQUEST | DEPFLAG_ECL_ONLY);

+ 16 - 5
tools/esdlcomp/esdlgram.y

@@ -193,12 +193,19 @@ EspServiceStart
         CurService->tags = getClearCurMetaTags();
 
         StringBuffer minPingVer;
+        StringBuffer pingAuthFeature("none");
         for (MetaTagInfo* t = CurService->tags; t!=NULL; t = t->next)
         {
             if (streq("ping_min_ver",t->getName()))
             {
-                minPingVer.set(t->getString());
-                break;
+                if (minPingVer.isEmpty())
+                {
+                    minPingVer.set(t->getString());
+                }
+            }
+            else if (streq("ping_auth_feature", t->getName()))
+            {
+                pingAuthFeature.set(t->getString());
             }
         }
 
@@ -229,12 +236,16 @@ EspServiceStart
 
         EspMethodInfo *method=new EspMethodInfo("Ping", reqname.str(), respname.str());
 
+        CurMetaTags = NULL;
         if(minPingVer.length()!=0)
         {
-            CurMetaTags = NULL;
             AddMetaTag(new MetaTagInfo("min_ver", minPingVer.str()));
-            method->tags = getClearCurMetaTags();
-         }
+        }
+        if(pingAuthFeature.length()!=0)
+        {
+            AddMetaTag(new MetaTagInfo("auth_feature", pingAuthFeature.str()));
+        }
+        method->tags = getClearCurMetaTags();
 
         method->next=CurService->methods;
         CurService->methods=method;

+ 75 - 114
tools/hidl/hidlcomp.cpp

@@ -21,7 +21,10 @@
 
 #include "hidl_utils.hpp"
 #include "hidlcomp.h"
+#include "AccessMapGenerator.hpp"
 
+#include <algorithm>
+#include <list>
 #include <map>
 #include <set>
 #include <string>
@@ -5414,113 +5417,94 @@ void EspServInfo::write_factory_impl()
     outf(" IClient%s * create%sClient() {  return new CClient%s(); }\n", name_, name_, name_);
 }
 
-const char * translateAuthLevel(const char * level)
-{
-    /*
-     *  This method might belong in seclib where the enumeration is defined (selib.h)
-     *  enum SecAccessFlags
-     *  {
-     *     SecAccess_Unknown = -255,
-     *     SecAccess_None = 0,
-     *     SecAccess_Access = 1,
-     *     SecAccess_Read = 3,
-     *     SecAccess_Write = 7,
-     *     SecAccess_Full = 255
-     *   };
-    */
 
-    if (!level || !*level)
-    {
-        outs(2, "\n//FEATURE LEVEL NOT SET, DEFAULTING TO 'READ'\n");
-        return "SecAccess_Read";
-    }
+using HidlAccessMapGenerator = TAccessMapGenerator<const char*>;
+
+using HidlAccessMapScopeMapper = HidlAccessMapGenerator::ScopeMapper;
+
+struct HidlAccessMapLevelMapper : public HidlAccessMapGenerator::LevelMapper
+{
+    const char* levelUnavailable() const override { return "SecAccess_Unavailable"; }
+    const char* levelNone() const override { return "SecAccess_None"; }
+    const char* levelDeferred() const override { return "SecAccess_None"; }
+    const char* levelAccess() const override { return "SecAccess_Access"; }
+    const char* levelRead() const override { return "SecAccess_Read"; }
+    const char* levelWrite() const override { return "SecAccess_Write"; }
+    const char* levelFull() const override { return "SecAccess_Full"; }
+    const char* levelUnknown() const override { return "SecAccess_Unknown"; }
 
-    if (strieq(level, "NONE"))
+    bool isEqual(const char* lhs, const char* rhs) const override
     {
-        outs(2, "\n//WARNING: FEATURE LEVEL AUTHORIZATION HAS BEEN TURNED OFF!!\n");
-        return "SecAccess_None";
+        return (lhs != nullptr && rhs != nullptr && strieq(lhs, rhs));
     }
 
-    if (strieq(level, "DEFERRED"))
+    const char* toString(const char* level) const override
     {
-        outs(2, "\n//WARNING: AUTOMATIC FEATURE LEVEL AUTHORIZATION LOGIC HAS BEEN DEFERED TO IN METHOD(DEVELOPER'S RESPONSIBILITY)!!\n");
-        return "SecAccess_None";
+        return level;
     }
+};
 
-    if (strieq(level, "FULL"))
-        return "SecAccess_Full";
-    else if (strieq(level, "WRITE"))
-        return "SecAccess_Write";
-    else if (strieq(level, "READ"))
-        return "SecAccess_Read";
-    else if (strieq(level, "ACCESS"))
-        return "SecAccess_Access";
-
-    //we might need to throw here...
-    outf(2, "\n//FEATURE LEVEL VALUE '%s' INVALID: DEFAULTING REQUIRED LEVEL to 'FULL'!\n//Valid values are NONE, DEFERRED, ACCESS, READ, WRITE, FULL\n", level);
-    return "SecAccess_Full";
-}
-
-void writeAccessMap(const char * rawServiceAccessList, const char * methodname, int tabs)
+struct HidlAccessMapReporter : public HidlAccessMapGenerator::Reporter
 {
     StrBuffer indent;
-    for (int tabindex = 0; tabindex < tabs; tabindex++)
-        indent.append('\t');
 
-    outf("%sMapStringTo<SecAccessFlags> accessmap;\n", indent.str());
-    if (rawServiceAccessList && *rawServiceAccessList)
+    HidlAccessMapReporter(int tabs)
     {
-        int listlen = strlen(rawServiceAccessList);
-        StrBuffer currAccessName;
-        StrBuffer currAccessLevel;
-        bool nameComplete = false;
-
-        for (int i = 0; i <= listlen; i++ )
-        {
-            if (i == listlen || rawServiceAccessList[i] == ',')
-            {
-                if (nameComplete == false)
-                {
-                    if (strieq(currAccessName, "NONE") || strieq(currAccessName, "DEFERRED"))
-                    {
-                        outf("\n//WARNING: Developer has suppressed automatic feature level authorization, ensure this behavior is correct!\n");
-                        currAccessName.clear();
-                        continue;
-                    }
-                    else
-                        outf("\nError: Access level must be declared in service definition: %s. Example: ESPservice [%s(\"myAccessFeature:FULL\"]\n", currAccessName.str(), FEATEACCESSATTRIBUTE);
-                }
+        for (int tabindex = 0; tabindex < tabs; tabindex++)
+            indent.append('\t');
+    }
 
-                outf("%saccessmap.setValue(\"%s\", %s);\n", indent.str(), currAccessName.str(), translateAuthLevel(currAccessLevel.str()));
-                currAccessName.clear();
-                currAccessLevel.clear();
-                nameComplete = false;
-                continue;
-            }
-            else if (rawServiceAccessList[i] == ':')
-            {
-                if (currAccessName.length()==0)
-                {
-                    currAccessName.setf("%sAccess", methodname);
-                    outf("\n//processaccesslist: defaulted current name to : %s\n", currAccessName.str());
-                }
+    bool reportInfo() const override { return false; }
+    bool reportDebug() const override { return false; }
 
-                nameComplete = true;
-                continue;
-            }
-            else if (rawServiceAccessList[i] == '"')
-                continue;
+    void preEntry(size_t termCount) const override
+    {
+        outf("%sMapStringTo<SecAccessFlags> accessmap;\n", indent.str());
+    }
+    void entry(const char* name, const char* level) const override
+    {
+        outf("%saccessmap.setValue(\"%s\", %s);\n", indent.str(), name, level);
+    }
 
-            if (!nameComplete)
-                currAccessName.append(rawServiceAccessList[i]);
-            else
-                currAccessLevel.append(rawServiceAccessList[i]);
-        }
+protected:
+    void reportError(const char* fmt, va_list& args) const override
+    {
+        reportSomething("\nERROR: ", fmt, args);
     }
-    else
+    void reportWarning(const char* fmt, va_list& args) const override
+    {
+        reportSomething("//WARNING: ", fmt, args);
+    }
+    void reportInfo(const char* fmt, va_list& args) const override
+    {
+        reportSomething("//INFO: ", fmt, args);
+    }
+    void reportDebug(const char* fmt, va_list& args) const override
     {
-        outf("\n%saccessmap.setValue(\"%sAccess\", %s);\n", indent.str(), methodname, "SecAccess_Read"); //This seems to be the default per seclib
+        reportSomething("//DEBUG: ", fmt, args);
+    }
+
+    inline void reportSomething(const char* prefix, const char* fmt, va_list& args) const
+    {
+        outs(prefix);
+        voutf(fmt, args);
+        outs("\n");
     }
+};
+
+void writeAccessMap(int indentLevel, EspServInfo& svci, const char* serviceName, const char* serviceFragment, EspMethodInfo& mthi)
+{
+    HidlAccessMapScopeMapper scopeMapper({"EsdlService", "EsdlMethod"});
+    HidlAccessMapLevelMapper levelMapper;
+    HidlAccessMapReporter    reporter(indentLevel);
+    HidlAccessMapGenerator   generator(scopeMapper, levelMapper, reporter);
+
+    generator.setVariable("service", serviceName);
+    generator.setVariable("method", mthi.getName());
+    generator.insertScope("EsdlService", serviceFragment);
+    generator.insertScope("EsdlMethod", mthi.getMetaString(FEATEACCESSATTRIBUTE, NULL));
+    generator.setDefaultSecurity("${service}Access:FULL");
+    generator.generateMap();
 }
 
 void EspServInfo::write_esp_binding_ipp()
@@ -5648,8 +5632,6 @@ void EspServInfo::write_esp_binding()
 
     StrBuffer servicefeatureurl;
     getMetaStringValue(servicefeatureurl,FEATEACCESSATTRIBUTE);
-    if (servicefeatureurl.length() == 0)
-        outf("ESDL Error: %s service definition must declare default feature access. Example 'ESPservice [%s(\"MyServiceAccess:FULL\")]'", name_, FEATEACCESSATTRIBUTE);
 
     outf("\nC%sSoapBinding::C%sSoapBinding(http_soap_log_level level):CHttpSoapBinding(NULL, NULL, NULL, level)\n{\n\tinit_strings();\n\tsetWsdlVersion(%s);", name_, name_, wsdlVer.str());
     outf("\n}\n");
@@ -5747,18 +5729,7 @@ void EspServInfo::write_esp_binding()
         if (!bHandleExceptions)
             bHandleExceptions = 0 != getMetaInt("exceptions_inline", 0);
 
-        const char * methodAccess = mthi->getMetaString(FEATEACCESSATTRIBUTE, NULL);
-        StrBuffer servicefeatureurl;
-        getMetaStringValue(servicefeatureurl,FEATEACCESSATTRIBUTE);
-
-        if (methodAccess && *methodAccess)
-        {
-            if (servicefeatureurl.length() != 0)
-                servicefeatureurl.append(",");
-            servicefeatureurl.append(methodAccess);
-        }
-
-        writeAccessMap(servicefeatureurl.str(),name_, 2);
+        writeAccessMap(2, *this, name_, servicefeatureurl, *mthi);
 
         StrBuffer clearCacheGroupIDs;
         if (mthi->hasMetaTag("clear_cache_group"))
@@ -6219,19 +6190,9 @@ void EspServInfo::write_esp_binding()
             outf("\t\t\tcheckRequest(context);\n");
             outf("\t\t\tC%s* resp = new C%s(\"%s\");\n", mthi->getResp(), mthi->getResp(), name_);
             outf("\t\t\tesp_response.setown(resp);\n");
-            
-            const char * methodAccess = mthi->getMetaString(FEATEACCESSATTRIBUTE, NULL);
-            StrBuffer servicefeatureurl;
-            getMetaStringValue(servicefeatureurl,FEATEACCESSATTRIBUTE);
 
-            if (methodAccess && *methodAccess)
-            {
-                if (servicefeatureurl.length() != 0)
-                    servicefeatureurl.append(",");
-                servicefeatureurl.append(methodAccess);
-            }
+            writeAccessMap(3, *this, name_, servicefeatureurl, *mthi);
 
-            writeAccessMap(servicefeatureurl.str(),name_, 3);
             if (bHandleExceptions)
             {
                 outf("\t\t\tsource.setf(\"%s::%%s()\", method);\n", name_);

+ 16 - 5
tools/hidl/hidlgram.y

@@ -196,12 +196,19 @@ EspServiceStart
         CurService->tags = getClearCurMetaTags();
 
         StrBuffer minPingVer;
+        StrBuffer pingAuthFeature("none");
         for (MetaTagInfo* t = CurService->tags; t!=NULL; t = t->next)
         {
             if (streq("ping_min_ver",t->getName()))
             {
-                minPingVer.set(t->getString());
-                break;
+                if (minPingVer.length()==0)
+                {
+                    minPingVer.set(t->getString());
+                }
+            }
+            else if (streq("ping_auth_feature", t->getName()))
+            {
+                pingAuthFeature.set(t->getString());
             }
         }
 
@@ -233,12 +240,16 @@ EspServiceStart
 
         EspMethodInfo *method=new EspMethodInfo("Ping", reqname.str(), respname.str());
 
+        CurMetaTags = NULL;
         if(minPingVer.length()!=0)
         {
-            CurMetaTags = NULL;
             AddMetaTag(new MetaTagInfo("min_ver", minPingVer.str()));
-            method->tags = getClearCurMetaTags();
-         }
+        }
+        if (pingAuthFeature.length()!=0)
+        {
+            AddMetaTag(new MetaTagInfo("auth_feature", pingAuthFeature.str()));
+        }
+        method->tags = getClearCurMetaTags();
 
         method->next=CurService->methods;
         CurService->methods=method;