You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ni...@apache.org on 2021/02/23 09:10:39 UTC

[atlas] branch branch-2.0 updated (8c41fc0 -> 2bb9868)

This is an automated email from the ASF dual-hosted git repository.

nixon pushed a change to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git.


    from 8c41fc0  ATLAS-4169: Add Hive Location Path entities to HMS Hook
     new d3d5160  ATLAS-4158 : Atlas authorization for Add/Update/Remove classification on entities.
     new 3084ed1  ATLAS-4135 [Atlas: Glossary Term Bulk Import] It will be good to ignore the glossaries and terms that are already present instead of failing the bulk import. ATLAS-4139 [Atlas: Glossary Term Bulk Import] When AdditionalAttributes is not provided in key:value format, the error message does not convey that.
     new d63812a  ATLAS-4146 [Atlas: Glossary] On updating the related terms, UI allows the user to add the already added term
     new 059ea24  ATLAS-4167:UI Large no. of calls are getting generated while rendering search results fixed
     new 1492590  ATLAS-3186:UI Background navigation is possible when 'Advanced Search Queries' popup is active.
     new 2bb9868  ATLAS-3376: UI V2 Fixed When no Catalogs are present, user should be presented with an appropriate message when trying to associate Category to Term.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../authorize/simple/AtlasSimpleAuthorizer.java    |  48 ++--
 .../authorize/simple/AtlasSimpleAuthzPolicy.java   |  50 ++--
 .../main/resources/atlas-simple-authz-policy.json  |  42 ++--
 .../simple/AtlasSimpleAuthorizerTest.java          | 260 ++++++++++++++++++---
 .../test/resources/atlas-simple-authz-policy.json  |  92 +++++++-
 dashboardv2/public/js/utils/Helper.js              |   5 +-
 .../js/views/detail_page/DetailPageLayoutView.js   |  57 +++--
 .../js/views/glossary/GlossaryDetailLayoutView.js  |  89 +++----
 .../js/views/search/SearchResultLayoutView.js      |  67 ++++--
 dashboardv3/public/js/utils/Helper.js              |   5 +-
 .../js/views/detail_page/DetailPageLayoutView.js   |  61 +++--
 .../js/views/glossary/GlossaryDetailLayoutView.js  |  89 +++----
 .../js/views/search/SearchResultLayoutView.js      |  78 +++++--
 distro/src/conf/atlas-simple-authz-policy.json     |  38 +--
 .../org/apache/atlas/glossary/GlossaryService.java |  33 ++-
 .../apache/atlas/glossary/GlossaryTermUtils.java   |   3 +-
 16 files changed, 727 insertions(+), 290 deletions(-)


[atlas] 04/06: ATLAS-4167:UI Large no. of calls are getting generated while rendering search results fixed

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 059ea24049d337df6a947d9e6838664b903b2da4
Author: prasad pawar <pr...@freestoneinfotech.com>
AuthorDate: Thu Feb 18 19:25:51 2021 +0530

    ATLAS-4167:UI Large no. of calls are getting generated while rendering search results fixed
    
    (cherry picked from commit 5aab9b0c6d1379d3751e0d13f06819f143617fe4)
---
 dashboardv2/public/js/views/search/SearchResultLayoutView.js | 11 ++++++++++-
 dashboardv3/public/js/views/search/SearchResultLayoutView.js | 11 ++++++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/dashboardv2/public/js/views/search/SearchResultLayoutView.js b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
index 0401049..9db1b54 100644
--- a/dashboardv2/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
@@ -246,6 +246,7 @@ define(['require',
             },
             onRender: function() {
                 var that = this;
+                this.checkEntityImage = {};
                 this.commonTableOptions = {
                     collection: this.searchCollection,
                     includePagination: false,
@@ -707,6 +708,7 @@ define(['require',
                             var getImageData = function(options) {
                                 var imagePath = options.imagePath,
                                     returnImgUrl = null;
+                                that.checkEntityImage[model.get('guid')] = false;
                                 $.ajax({
                                         "url": imagePath,
                                         "method": "get",
@@ -718,6 +720,7 @@ define(['require',
                                                 "imagePath": Utils.getEntityIconPath({ entityData: obj, errorUrl: imagePath })
                                             });
                                         } else if (data) {
+                                            that.checkEntityImage[model.get('guid')] = imagePath;
                                             returnImgUrl = imagePath;
                                             that.$("img[data-imgGuid='" + obj.guid + "']").removeClass("searchTableLogoLoader").attr("src", imagePath);
                                         }
@@ -725,7 +728,13 @@ define(['require',
                             }
                             var img = "";
                             img = "<div><img data-imgGuid='" + obj.guid + "' class='searchTableLogoLoader'></div>";
-                            getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });
+                            if (that.checkEntityImage[model.get('guid')] == undefined) {
+                                getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });
+                            } else {
+                                if (that.checkEntityImage[model.get('guid')] != false) {
+                                    img = "<div><img data-imgGuid='" + obj.guid + "' src='" + that.checkEntityImage[model.get('guid')] + "'></div>";
+                                }
+                            }
                             return (img + nameHtml);
                         }
                     })
diff --git a/dashboardv3/public/js/views/search/SearchResultLayoutView.js b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
index 67679bb..d98d6e2 100644
--- a/dashboardv3/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
@@ -255,6 +255,7 @@ define(['require',
                 if (Utils.getUrlState.isSearchTab()) {
                     this.$(".action-box").hide();
                 }
+                this.checkEntityImage = {};
                 this.commonTableOptions = {
                     collection: this.searchCollection,
                     includePagination: false,
@@ -719,6 +720,7 @@ define(['require',
                             var getImageData = function(options) {
                                 var imagePath = options.imagePath,
                                     returnImgUrl = null;
+                                that.checkEntityImage[model.get('guid')] = false;
                                 $.ajax({
                                         "url": imagePath,
                                         "method": "get",
@@ -730,6 +732,7 @@ define(['require',
                                                 "imagePath": Utils.getEntityIconPath({ entityData: obj, errorUrl: imagePath })
                                             });
                                         } else if (data) {
+                                            that.checkEntityImage[model.get('guid')] = imagePath;
                                             returnImgUrl = imagePath;
                                             that.$("img[data-imgGuid='" + obj.guid + "']").removeClass("searchTableLogoLoader").attr("src", imagePath);
                                         }
@@ -737,7 +740,13 @@ define(['require',
                             }
                             var img = "";
                             img = "<div><img data-imgGuid='" + obj.guid + "' class='searchTableLogoLoader'></div>";
-                            getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });
+                            if (that.checkEntityImage[model.get('guid')] == undefined) {
+                                getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });
+                            } else {
+                                if (that.checkEntityImage[model.get('guid')] != false) {
+                                    img = "<div><img data-imgGuid='" + obj.guid + "' src='" + that.checkEntityImage[model.get('guid')] + "'></div>";
+                                }
+                            }
                             return (img + nameHtml);
                         }
                     })


[atlas] 05/06: ATLAS-3186:UI Background navigation is possible when 'Advanced Search Queries' popup is active.

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 1492590c96505ce02913304c00c86c6cfbf085e7
Author: prasad pawar <pr...@freestoneinfotech.com>
AuthorDate: Fri Feb 19 10:51:19 2021 +0530

    ATLAS-3186:UI Background navigation is possible when 'Advanced Search Queries' popup is active.
    
    (cherry picked from commit f84993293127c2036667c8fbec30469d85e52991)
---
 dashboardv2/public/js/utils/Helper.js | 5 ++++-
 dashboardv3/public/js/utils/Helper.js | 5 ++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/dashboardv2/public/js/utils/Helper.js b/dashboardv2/public/js/utils/Helper.js
index b78077f..f211bd0 100644
--- a/dashboardv2/public/js/utils/Helper.js
+++ b/dashboardv2/public/js/utils/Helper.js
@@ -371,5 +371,8 @@ define(['require',
             container: 'body'
         });
     }
-
+    //For closing the modal on browsers navigation
+    $(window).on('popstate', function(){
+        $('body').find('.modal-dialog .close').click();
+    });
 })
\ No newline at end of file
diff --git a/dashboardv3/public/js/utils/Helper.js b/dashboardv3/public/js/utils/Helper.js
index ed2fcc0..04d3882 100644
--- a/dashboardv3/public/js/utils/Helper.js
+++ b/dashboardv3/public/js/utils/Helper.js
@@ -390,5 +390,8 @@ define(['require',
             container: 'body'
         });
     }
-
+    //For closing the modal on browsers navigation
+    $(window).on('popstate', function(){
+        $('body').find('.modal-dialog .close').click();
+    });
 })
\ No newline at end of file


[atlas] 06/06: ATLAS-3376: UI V2 Fixed When no Catalogs are present, user should be presented with an appropriate message when trying to associate Category to Term.

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 2bb9868966d76ef05c3d3652a515ad1904736658
Author: prasad pawar <pr...@freestoneinfotech.com>
AuthorDate: Tue Feb 23 13:56:13 2021 +0530

    ATLAS-3376: UI V2 Fixed When no Catalogs are present, user should be presented with an appropriate message when trying to associate Category to Term.
    
    (cherry picked from commit c551f66556e01d69f2918831b8b93b0397b04d75)
---
 .../js/views/detail_page/DetailPageLayoutView.js   | 57 +++++++++-----
 .../js/views/glossary/GlossaryDetailLayoutView.js  | 89 +++++++++++-----------
 .../js/views/search/SearchResultLayoutView.js      | 56 +++++++++-----
 .../js/views/detail_page/DetailPageLayoutView.js   | 61 ++++++++++-----
 .../js/views/glossary/GlossaryDetailLayoutView.js  | 89 +++++++++++-----------
 .../js/views/search/SearchResultLayoutView.js      | 67 +++++++++++-----
 6 files changed, 258 insertions(+), 161 deletions(-)

diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index b878f6d..e83212f 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -558,29 +558,46 @@ define(['require',
                     });
                 });
             },
-            onClickAddTermBtn: function(e) {
+            assignTermModalView: function(glossaryCollection, obj) {
                 var that = this,
-                    entityGuid = that.id,
-                    entityObj = this.collection.first().get('entity'),
-                    associatedTerms = [];
-                if (entityObj && entityObj.relationshipAttributes && entityObj.relationshipAttributes.meanings) {
-                    associatedTerms = entityObj.relationshipAttributes.meanings;
-                }
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var view = new AssignTermLayoutView({
-                        guid: that.id,
-                        callback: function() {
-                            that.fetchCollection();
-                        },
-                        associatedTerms: associatedTerms,
-                        showLoader: that.showLoader.bind(that),
-                        hideLoader: that.hideLoader.bind(that),
-                        glossaryCollection: that.glossaryCollection
+                    terms = 0;
+                _.each(glossaryCollection.fullCollection.models, function(model) {
+                    if (model.get('terms')) {
+                        terms += model.get('terms').length;
+                    };
+                });
+                if (terms) {
+                    require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
+                        var view = new AssignTermLayoutView({
+                            guid: obj.guid,
+                            callback: function() {
+                                that.fetchCollection();
+                            },
+                            associatedTerms: obj.associatedTerms,
+                            showLoader: that.showLoader.bind(that),
+                            hideLoader: that.hideLoader.bind(that),
+                            glossaryCollection: glossaryCollection
+                        });
+                        view.modal.on('ok', function() {
+                            Utils.showTitleLoader(that.$('.page-title .fontLoader'), that.$('.entityDetail'));
+                        });
                     });
-                    view.modal.on('ok', function() {
-                        Utils.showTitleLoader(that.$('.page-title .fontLoader'), that.$('.entityDetail'));
+                } else {
+                    Utils.notifyInfo({
+                        content: "There are no available terms that can be associated with this entity"
                     });
-                });
+                }
+            },
+            onClickAddTermBtn: function(e) {
+                var entityObj = this.collection.first().get('entity'),
+                    obj = {
+                        guid: this.id,
+                        associatedTerms: [],
+                    };
+                this.assignTermModalView(this.glossaryCollection, obj);
+                if (entityObj && entityObj.relationshipAttributes && entityObj.relationshipAttributes.meanings) {
+                    obj.associatedTerms = entityObj.relationshipAttributes.meanings;
+                }
             },
             renderEntityDetailTableLayoutView: function(obj) {
                 var that = this;
diff --git a/dashboardv2/public/js/views/glossary/GlossaryDetailLayoutView.js b/dashboardv2/public/js/views/glossary/GlossaryDetailLayoutView.js
index d9f1fb9..bb8fe8f 100644
--- a/dashboardv2/public/js/views/glossary/GlossaryDetailLayoutView.js
+++ b/dashboardv2/public/js/views/glossary/GlossaryDetailLayoutView.js
@@ -165,7 +165,7 @@ define(['require',
                     }
                 };
                 events["click " + this.ui.addTerm] = 'onClickAddTermBtn';
-                events["click " + this.ui.addCategory] = 'onClickAddCategoryBtn';
+                events["click " + this.ui.addCategory] = 'onClickAddTermBtn';
                 events["click " + this.ui.addTag] = 'onClickAddTagBtn';
                 return events;
             },
@@ -336,60 +336,63 @@ define(['require',
                 this.ui.tagList.find("span.btn").remove();
                 this.ui.tagList.prepend(tagData);
             },
+            getCategoryTermCount: function(collection, matchString) {
+                var terms = 0;
+                _.each(collection, function(model) {
+                    if (model.get(matchString)) {
+                        terms += model.get(matchString).length;
+                    }
+                });
+                return terms;
+            },
             onClickAddTermBtn: function(e) {
-                var that = this;
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var glossary = that.glossaryCollection;
-                    if (that.value && that.value.gId) {
-                        var foundModel = that.glossaryCollection.find({ guid: that.value.gId });
-                        if (foundModel) {
-                            glossary = new VGlossaryList([foundModel.toJSON()], {
-                                comparator: function(item) {
-                                    return item.get("name");
-                                }
-                            });
-                        }
+                var glossary = this.glossaryCollection;
+                if (this.value && this.value.gId) {
+                    var foundModel = this.glossaryCollection.find({ guid: this.value.gId });
+                    if (foundModel) {
+                        glossary = new VGlossaryList([foundModel.toJSON()], {
+                            comparator: function(item) {
+                                return item.get("name");
+                            }
+                        });
                     }
-
-                    var view = new AssignTermLayoutView({
-                        categoryData: that.data,
-                        associatedTerms: that.data && that.data.terms && that.data.terms.length > 0 ? that.data.terms : [],
-                        isCategoryView: that.isCategoryView,
+                }
+                var obj = {
                         callback: function() {
-                            that.getData();
+                            this.getData();
                         },
-                        glossaryCollection: glossary
+                        glossaryCollection: glossary,
+                    },
+                    emptyListMessage = this.isCategoryView ? "There are no available terms that can be associated with this category" : "There are no available categories that can be associated with this term";
+
+                if (this.isCategoryView) {
+                    obj = _.extend(obj, {
+                        categoryData: this.data,
+                        associatedTerms: (this.data && this.data.terms && this.data.terms.length > 0) ? this.data.terms : [],
+                        isCategoryView: this.isCategoryView,
                     });
-                    view.modal.on('ok', function() {
-                        that.hideLoader();
+                } else {
+                    obj = _.extend(obj, {
+                        termData: this.data,
+                        isTermView: this.isTermView,
                     });
-                });
+                }
+                if (this.getCategoryTermCount(glossary.fullCollection.models, this.isCategoryView ? "terms" : "categories")) {
+                    this.AssignTermLayoutViewModal(obj);
+                } else {
+                    Utils.notifyInfo({
+                        content: emptyListMessage
+                    });
+                }
             },
-            onClickAddCategoryBtn: function(e) {
+            AssignTermLayoutViewModal: function(termCategoryObj) {
                 var that = this;
                 require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var glossary = that.glossaryCollection;
-                    if (that.value && that.value.gId) {
-                        var foundModel = that.glossaryCollection.find({ guid: that.value.gId });
-                        if (foundModel) {
-                            glossary = new VGlossaryList([foundModel.toJSON()], {
-                                comparator: function(item) {
-                                    return item.get("name");
-                                }
-                            });
-                        }
-                    }
-                    var view = new AssignTermLayoutView({
-                        termData: that.data,
-                        isTermView: that.isTermView,
-                        callback: function() {
-                            that.getData();
-                        },
-                        glossaryCollection: glossary
-                    });
+                    var view = new AssignTermLayoutView(termCategoryObj);
                     view.modal.on('ok', function() {
                         that.hideLoader();
                     });
+
                 });
             },
             onClickAddTagBtn: function(e) {
diff --git a/dashboardv2/public/js/views/search/SearchResultLayoutView.js b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
index 9db1b54..98c9ec0 100644
--- a/dashboardv2/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
@@ -15,7 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 define(['require',
     'backbone',
     'table-dragger',
@@ -1123,31 +1122,52 @@ define(['require',
                     that.addTagModalView(guid);
                 }
             },
+            //This function checks for the lenght of Available terms and modal for adding terms is displayed accordingly.
+            assignTermModalView: function(glossaryCollection, obj) {
+                var that = this,
+                    terms = 0;
+                _.each(glossaryCollection.fullCollection.models, function(model) {
+                    if (model.get('terms')) {
+                        terms += model.get('terms').length;
+                    };
+                });
+                if (terms) {
+                    require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
+                        var view = new AssignTermLayoutView({
+                            guid: obj.guid,
+                            multiple: obj.multiple,
+                            associatedTerms: obj.associatedTerms,
+                            callback: function() {
+                                that.multiSelectEntity = [];
+                                that.$('.multiSelectTag,.multiSelectTerm').hide();
+                                that.fetchCollection();
+                            },
+                            glossaryCollection: glossaryCollection,
+                        });
+                    });
+                } else {
+                    Utils.notifyInfo({
+                        content: "There are no available terms"
+                    });
+                }
+            },
             onClickAddTermBtn: function(e) {
                 var that = this,
                     guid = "",
                     entityGuid = $(e.currentTarget).data("guid"),
-                    associatedTerms = undefined,
-                    multiple = undefined,
+                    obj = {
+                        guid: entityGuid,
+                        multiple: undefined,
+                        associatedTerms: undefined,
+                    },
                     isTermMultiSelect = $(e.currentTarget).hasClass('multiSelectTerm');
+
+                that.assignTermModalView(this.glossaryCollection, obj);
                 if (isTermMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {
-                    multiple = this.multiSelectEntity;
+                    obj.multiple = this.multiSelectEntity;
                 } else if (entityGuid) {
-                    associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');
+                    obj.associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');
                 }
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var view = new AssignTermLayoutView({
-                        guid: entityGuid,
-                        multiple: multiple,
-                        associatedTerms: associatedTerms,
-                        callback: function() {
-                            that.multiSelectEntity = [];
-                            that.$('.multiSelectTag,.multiSelectTerm').hide();
-                            that.fetchCollection();
-                        },
-                        glossaryCollection: that.glossaryCollection,
-                    });
-                });
             },
             onClickTagCross: function(e) {
                 var that = this,
diff --git a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
index dbbbcde..a18984e 100644
--- a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
@@ -565,29 +565,54 @@ define(['require',
                     });
                 });
             },
+            //This function checks for the lenght of Available terms and modal for adding terms is displayed accordingly.
+            assignTermModalView: function(glossaryCollection, obj) {
+                var that = this,
+                    terms = 0;
+                _.each(glossaryCollection.fullCollection.models, function(model) {
+                    if (model.get('terms')) {
+                        terms += model.get('terms').length;
+                    };
+                });
+                if (terms) {
+                    require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
+                        var view = new AssignTermLayoutView({
+                            guid: obj.guid,
+                            callback: function() {
+                                that.fetchCollection();
+                            },
+                            associatedTerms: obj.associatedTerms,
+                            showLoader: that.showLoader.bind(that),
+                            hideLoader: that.hideLoader.bind(that),
+                            glossaryCollection: glossaryCollection
+                        });
+                        view.modal.on('ok', function() {
+                            Utils.showTitleLoader(that.$('.page-title .fontLoader'), that.$('.entityDetail'));
+                        });
+                    });
+                } else {
+                    Utils.notifyInfo({
+                        content: "There are no available terms that can be associated with this entity"
+                    });
+                }
+            },
             onClickAddTermBtn: function(e) {
                 var that = this,
-                    entityGuid = that.id,
                     entityObj = this.collection.first().get('entity'),
-                    associatedTerms = [];
+                    glossaryData = null,
+                    obj = {
+                        guid: this.id,
+                        associatedTerms: [],
+                    };
+                this.glossaryCollection.fetch({
+                    success: function(glossaryCollection) {
+                        that.assignTermModalView(glossaryCollection, obj);
+                    },
+                    reset: true,
+                });
                 if (entityObj && entityObj.relationshipAttributes && entityObj.relationshipAttributes.meanings) {
-                    associatedTerms = entityObj.relationshipAttributes.meanings;
+                    obj.associatedTerms = entityObj.relationshipAttributes.meanings;
                 }
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var view = new AssignTermLayoutView({
-                        guid: that.id,
-                        callback: function() {
-                            that.fetchCollection();
-                        },
-                        associatedTerms: associatedTerms,
-                        showLoader: that.showLoader.bind(that),
-                        hideLoader: that.hideLoader.bind(that),
-                        glossaryCollection: that.glossaryCollection
-                    });
-                    view.modal.on('ok', function() {
-                        Utils.showTitleLoader(that.$('.page-title .fontLoader'), that.$('.entityDetail'));
-                    });
-                });
             },
             renderEntityDetailTableLayoutView: function(obj) {
                 var that = this;
diff --git a/dashboardv3/public/js/views/glossary/GlossaryDetailLayoutView.js b/dashboardv3/public/js/views/glossary/GlossaryDetailLayoutView.js
index 951281c..551e229 100644
--- a/dashboardv3/public/js/views/glossary/GlossaryDetailLayoutView.js
+++ b/dashboardv3/public/js/views/glossary/GlossaryDetailLayoutView.js
@@ -171,7 +171,7 @@ define(['require',
                     Utils.backButtonClick();
                 }
                 events["click " + this.ui.addTerm] = 'onClickAddTermBtn';
-                events["click " + this.ui.addCategory] = 'onClickAddCategoryBtn';
+                events["click " + this.ui.addCategory] = 'onClickAddTermBtn';
                 events["click " + this.ui.addTag] = 'onClickAddTagBtn';
                 return events;
             },
@@ -351,60 +351,63 @@ define(['require',
                 this.ui.tagList.find("span.btn").remove();
                 this.ui.tagList.prepend(tagData);
             },
+            getCategoryTermCount: function(collection, matchString) {
+                var terms = 0;
+                _.each(collection, function(model) {
+                    if (model.get(matchString)) {
+                        terms += model.get(matchString).length;
+                    }
+                });
+                return terms;
+            },
             onClickAddTermBtn: function(e) {
-                var that = this;
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var glossary = that.glossaryCollection;
-                    if (that.value && that.value.gId) {
-                        var foundModel = that.glossaryCollection.find({ guid: that.value.gId });
-                        if (foundModel) {
-                            glossary = new VGlossaryList([foundModel.toJSON()], {
-                                comparator: function(item) {
-                                    return item.get("name");
-                                }
-                            });
-                        }
+                var glossary = this.glossaryCollection;
+                if (this.value && this.value.gId) {
+                    var foundModel = this.glossaryCollection.find({ guid: this.value.gId });
+                    if (foundModel) {
+                        glossary = new VGlossaryList([foundModel.toJSON()], {
+                            comparator: function(item) {
+                                return item.get("name");
+                            }
+                        });
                     }
-
-                    var view = new AssignTermLayoutView({
-                        categoryData: that.data,
-                        associatedTerms: that.data && that.data.terms && that.data.terms.length > 0 ? that.data.terms : [],
-                        isCategoryView: that.isCategoryView,
+                }
+                var obj = {
                         callback: function() {
-                            that.getData();
+                            this.getData();
                         },
-                        glossaryCollection: glossary
+                        glossaryCollection: glossary,
+                    },
+                    emptyListMessage = this.isCategoryView ? "There are no available terms that can be associated with this category" : "There are no available categories that can be associated with this term";
+
+                if (this.isCategoryView) {
+                    obj = _.extend(obj, {
+                        categoryData: this.data,
+                        associatedTerms: (this.data && this.data.terms && this.data.terms.length > 0) ? this.data.terms : [],
+                        isCategoryView: this.isCategoryView,
                     });
-                    view.modal.on('ok', function() {
-                        that.hideLoader();
+                } else {
+                    obj = _.extend(obj, {
+                        termData: this.data,
+                        isTermView: this.isTermView,
                     });
-                });
+                }
+                if (this.getCategoryTermCount(glossary.fullCollection.models, this.isCategoryView ? "terms" : "categories")) {
+                    this.AssignTermLayoutViewModal(obj);
+                } else {
+                    Utils.notifyInfo({
+                        content: emptyListMessage
+                    });
+                }
             },
-            onClickAddCategoryBtn: function(e) {
+            AssignTermLayoutViewModal: function(termCategoryObj) {
                 var that = this;
                 require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var glossary = that.glossaryCollection;
-                    if (that.value && that.value.gId) {
-                        var foundModel = that.glossaryCollection.find({ guid: that.value.gId });
-                        if (foundModel) {
-                            glossary = new VGlossaryList([foundModel.toJSON()], {
-                                comparator: function(item) {
-                                    return item.get("name");
-                                }
-                            });
-                        }
-                    }
-                    var view = new AssignTermLayoutView({
-                        termData: that.data,
-                        isTermView: that.isTermView,
-                        callback: function() {
-                            that.getData();
-                        },
-                        glossaryCollection: glossary
-                    });
+                    var view = new AssignTermLayoutView(termCategoryObj);
                     view.modal.on('ok', function() {
                         that.hideLoader();
                     });
+
                 });
             },
             onClickAddTagBtn: function(e) {
diff --git a/dashboardv3/public/js/views/search/SearchResultLayoutView.js b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
index d98d6e2..d5883ca 100644
--- a/dashboardv3/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
@@ -153,7 +153,7 @@ define(['require',
              * @constructs
              */
             initialize: function(options) {
-                _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection', 'typeHeaders', 'searchVent', 'enumDefCollection', 'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection', 'termName', 'businessMetadataDefCollection', 'profileDBView'));
+                _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection', 'typeHeaders', 'searchVent', 'categoryEvent', 'enumDefCollection', 'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection', 'termName', 'businessMetadataDefCollection', 'profileDBView'));
                 this.entityModel = new VEntity();
                 this.searchCollection = new VSearchList();
                 this.limit = 25;
@@ -248,13 +248,17 @@ define(['require',
                 }, this);
                 this.listenTo(this.searchCollection, "backgrid:sorted", function(model, response) {
                     this.checkTableFetch();
-                }, this)
+                }, this);
+                this.listenTo(this.categoryEvent, "Sucess:TermSearchResultPage", function() {
+                    this.glossaryCollection.fetch({ reset: true });
+                });
             },
             onRender: function() {
                 var that = this;
                 if (Utils.getUrlState.isSearchTab()) {
                     this.$(".action-box").hide();
                 }
+
                 this.checkEntityImage = {};
                 this.commonTableOptions = {
                     collection: this.searchCollection,
@@ -1134,32 +1138,57 @@ define(['require',
                     that.addTagModalView(guid);
                 }
             },
+            //This function checks for the lenght of Available terms and modal for adding terms is displayed accordingly.
+            assignTermModalView: function(glossaryCollection, obj) {
+                var that = this,
+                    terms = 0;
+                _.each(glossaryCollection.fullCollection.models, function(model) {
+                    if (model.get('terms')) {
+                        terms += model.get('terms').length;
+                    };
+                });
+                if (terms) {
+                    require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
+                        var view = new AssignTermLayoutView({
+                            guid: obj.guid,
+                            multiple: obj.multiple,
+                            associatedTerms: obj.associatedTerms,
+                            callback: function() {
+                                that.multiSelectEntity = [];
+                                that.$('.multiSelectTag,.multiSelectTerm').hide();
+                                that.fetchCollection();
+                            },
+                            glossaryCollection: glossaryCollection,
+                        });
+                    });
+                } else {
+                    Utils.notifyInfo({
+                        content: "There are no available terms"
+                    });
+                }
+            },
             onClickAddTermBtn: function(e) {
                 var that = this,
                     guid = "",
                     entityGuid = $(e.currentTarget).data("guid"),
-                    associatedTerms = undefined,
-                    multiple = undefined,
+                    obj = {
+                        guid: entityGuid,
+                        multiple: undefined,
+                        associatedTerms: undefined,
+                    },
                     isTermMultiSelect = $(e.currentTarget).hasClass('multiSelectTerm');
+                this.glossaryCollection.fetch({
+                    success: function(glossaryCollection) {
+                        that.assignTermModalView(glossaryCollection, obj);
+                    },
+                    reset: true,
+                });
                 if (isTermMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {
-                    multiple = this.multiSelectEntity;
+                    obj.multiple = this.multiSelectEntity;
                 } else if (entityGuid) {
-                    associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');
+                    obj.associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');
                 }
-                require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {
-                    var view = new AssignTermLayoutView({
-                        guid: entityGuid,
-                        multiple: multiple,
-                        associatedTerms: associatedTerms,
-                        callback: function() {
-                            that.multiSelectEntity = [];
-                            that.$('.multiSelectTag,.multiSelectTerm').hide();
-                            that.fetchCollection();
 
-                        },
-                        glossaryCollection: that.glossaryCollection,
-                    });
-                });
             },
             onClickTagCross: function(e) {
                 var that = this,


[atlas] 03/06: ATLAS-4146 [Atlas: Glossary] On updating the related terms, UI allows the user to add the already added term

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit d63812a9367cde73e91f7be32a10af0fcf0d5cf2
Author: Mandar Ambawane <ma...@freestoneinfotech.com>
AuthorDate: Wed Feb 10 18:12:53 2021 +0530

    ATLAS-4146 [Atlas: Glossary] On updating the related terms, UI allows the user to add the already added term
    
    (cherry picked from commit c5c73250b48217c0cdcc706ac654f352938bea41)
---
 .../org/apache/atlas/glossary/GlossaryService.java | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
index 1da3279..df5fcbd 100644
--- a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
+++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
@@ -407,6 +407,11 @@ public class GlossaryService {
             throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
         }
 
+        String qualifiedName = getDuplicateGlossaryRelatedTerm(atlasGlossaryTerm);
+        if (StringUtils.isNotEmpty(qualifiedName)) {
+            throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_TERM_ALREADY_EXISTS, qualifiedName);
+        }
+
         AtlasGlossaryTerm storeObject = dataAccess.load(atlasGlossaryTerm);
         if (!storeObject.equals(atlasGlossaryTerm)) {
             atlasGlossaryTerm.setGuid(storeObject.getGuid());
@@ -1030,6 +1035,30 @@ public class GlossaryService {
         return StringUtils.containsAny(name, invalidNameChars);
     }
 
+    private String getDuplicateGlossaryRelatedTerm(AtlasGlossaryTerm atlasGlossaryTerm) throws AtlasBaseException {
+
+        Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> relatedTermsMap = atlasGlossaryTerm.getRelatedTerms();
+        for (Map.Entry<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> relatedTermsMapEntry : relatedTermsMap.entrySet()) {
+            Set<AtlasRelatedTermHeader> termHeaders = relatedTermsMapEntry.getValue();
+
+            if (CollectionUtils.isNotEmpty(termHeaders)) {
+                List<AtlasRelatedTermHeader> duplicateTermHeaders = termHeaders.stream()
+                        .collect(Collectors.groupingBy(AtlasRelatedTermHeader::getTermGuid))
+                        .values().stream()
+                        .filter(duplicates -> duplicates.size() > 1)
+                        .flatMap(Collection::stream)
+                        .collect(Collectors.toList());
+
+                if (CollectionUtils.isNotEmpty(duplicateTermHeaders) && duplicateTermHeaders.size() > 0) {
+                    String dupTermGuid = duplicateTermHeaders.get(0).getTermGuid();
+                    AtlasGlossaryTerm glossaryTerm = getTerm(dupTermGuid);
+                    return glossaryTerm.getQualifiedName();
+                }
+            }
+        }
+        return StringUtils.EMPTY;
+    }
+
     private String getDisplayText(AtlasGlossaryTerm term) {
         return term != null ? term.getName() : null;
     }


[atlas] 02/06: ATLAS-4135 [Atlas: Glossary Term Bulk Import] It will be good to ignore the glossaries and terms that are already present instead of failing the bulk import. ATLAS-4139 [Atlas: Glossary Term Bulk Import] When AdditionalAttributes is not provided in key:value format, the error message does not convey that.

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 3084ed1865c5b5aa788ec8d9be998fac1721784b
Author: Mandar Ambawane <ma...@freestoneinfotech.com>
AuthorDate: Tue Feb 16 12:42:22 2021 +0530

    ATLAS-4135 [Atlas: Glossary Term Bulk Import] It will be good to ignore the glossaries and terms that are already present instead of failing the bulk import.
    ATLAS-4139 [Atlas: Glossary Term Bulk Import] When AdditionalAttributes is not provided in key:value format, the error message does not convey that.
    
    (cherry picked from commit 5d0eba4e7a92afd11fd47f47d7352a976af430e0)
---
 .../src/main/java/org/apache/atlas/glossary/GlossaryService.java      | 4 +++-
 .../src/main/java/org/apache/atlas/glossary/GlossaryTermUtils.java    | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
index 6e10a96..1da3279 100644
--- a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
+++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
@@ -1104,7 +1104,9 @@ public class GlossaryService {
             try {
                 ret.add(createTerm(glossaryTerm));
             } catch (AtlasBaseException e) {
-                throw new AtlasBaseException(AtlasErrorCode.FAILED_TO_CREATE_GLOSSARY_TERM, e);
+                if (!e.getAtlasErrorCode().equals(AtlasErrorCode.GLOSSARY_TERM_ALREADY_EXISTS)) {
+                    throw new AtlasBaseException(AtlasErrorCode.FAILED_TO_CREATE_GLOSSARY_TERM, e);
+                }
             }
         }
 
diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryTermUtils.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryTermUtils.java
index 2c84ec7..0871ab5 100644
--- a/repository/src/main/java/org/apache/atlas/glossary/GlossaryTermUtils.java
+++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryTermUtils.java
@@ -623,7 +623,8 @@ public class GlossaryTermUtils extends GlossaryUtils {
                 if ((recordArray.length % 2) == 0) {
                     ret.put(recordArray[0], recordArray[1]);
                 } else {
-                    failedTermMsgs.add("\n" + "The Data in the uploaded file is incorrectly specified  : " + csvRecord);
+                    failedTermMsgs.add("\n" + "The Data in the uploaded file is incorrectly specified  : " + csvRecord
+                            + "\n" + "AdditionalAttributes needs to be a key:value pair");
                 }
             }
         }


[atlas] 01/06: ATLAS-4158 : Atlas authorization for Add/Update/Remove classification on entities.

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit d3d51603726336f00886e95a86f1ea4248d3a331
Author: nixonrodrigues <ni...@apache.org>
AuthorDate: Tue Feb 16 15:56:45 2021 +0530

    ATLAS-4158 : Atlas authorization for Add/Update/Remove classification on entities.
    
    (cherry picked from commit ea66c181ba0d592ce2aff998ed84e4afd30a3d41)
---
 .../authorize/simple/AtlasSimpleAuthorizer.java    |  48 ++--
 .../authorize/simple/AtlasSimpleAuthzPolicy.java   |  50 ++--
 .../main/resources/atlas-simple-authz-policy.json  |  42 ++--
 .../simple/AtlasSimpleAuthorizerTest.java          | 260 ++++++++++++++++++---
 .../test/resources/atlas-simple-authz-policy.json  |  92 +++++++-
 distro/src/conf/atlas-simple-authz-policy.json     |  38 +--
 6 files changed, 407 insertions(+), 123 deletions(-)

diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java
index 5636438..7b99e97 100644
--- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java
+++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java
@@ -42,6 +42,9 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_ADD_CLASSIFICATION;
+import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_REMOVE_CLASSIFICATION;
+import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_UPDATE_CLASSIFICATION;
 import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_CREATE;
 import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_DELETE;
 import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_READ;
@@ -53,6 +56,12 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer {
 
     private final static String WILDCARD_ASTERISK = "*";
 
+    private final static Set<AtlasPrivilege> CLASSIFICATION_PRIVILEGES = new HashSet<AtlasPrivilege>() {{
+                                                                                add(ENTITY_ADD_CLASSIFICATION);
+                                                                                add(ENTITY_REMOVE_CLASSIFICATION);
+                                                                                add(ENTITY_UPDATE_CLASSIFICATION);
+                                                                            }};
+
     private AtlasSimpleAuthzPolicy authzPolicy;
 
 
@@ -233,43 +242,38 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer {
             LOG.debug("==> SimpleAtlasAuthorizer.isAccessAllowed({})", request);
         }
 
+        boolean           ret            = false;
         final String      action         = request.getAction() != null ? request.getAction().getType() : null;
         final Set<String> entityTypes    = request.getEntityTypeAndAllSuperTypes();
         final String      entityId       = request.getEntityId();
-        final String      classification = request.getClassification() != null ? request.getClassification().getTypeName() : null;
         final String      attribute      = request.getAttributeName();
         final Set<String> entClsToAuthz  = new HashSet<>(request.getEntityClassifications());
         final Set<String> roles          = getRoles(request.getUser(), request.getUserGroups());
-        boolean hasEntityAccess          = false;
-        boolean hasClassificationsAccess = false;
 
         for (String role : roles) {
             List<AtlasEntityPermission> permissions = getEntityPermissionsForRole(role);
 
             if (permissions != null) {
                 for (AtlasEntityPermission permission : permissions) {
-                    // match entity-type/entity-id/label/business-metadata/attribute
-                    if (isMatchAny(entityTypes, permission.getEntityTypes()) && isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes())
-                         && isLabelMatch(request, permission) && isBusinessMetadataMatch(request, permission)) {
-                        // match permission/classification
-                        if (!hasEntityAccess) {
-                            if (isMatch(action, permission.getPrivileges()) && isMatch(classification, permission.getClassifications())) {
-                                hasEntityAccess = true;
-                            }
-                        }
-
-                        // match entity-classifications
-                        for (Iterator<String> iter = entClsToAuthz.iterator(); iter.hasNext();) {
+                    if (isMatch(action, permission.getPrivileges()) && isMatchAny(entityTypes, permission.getEntityTypes()) &&
+                        isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes()) &&
+                        isLabelMatch(request, permission) && isBusinessMetadataMatch(request, permission) && isClassificationMatch(request, permission)) {
+
+                        // 1. entity could have multiple classifications
+                        // 2. access for these classifications could be granted by multiple AtlasEntityPermission entries
+                        // 3. classifications allowed by the current permission will be removed from entClsToAuthz
+                        // 4. request will be allowed once entClsToAuthz is empty i.e. user has permission for all classifications
+                        for (Iterator<String> iter = entClsToAuthz.iterator(); iter.hasNext(); ) {
                             String entityClassification = iter.next();
 
-                            if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getClassifications())) {
+                            if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getEntityClassifications())) {
                                 iter.remove();
                             }
                         }
 
-                        hasClassificationsAccess = CollectionUtils.isEmpty(entClsToAuthz);
+                        ret = CollectionUtils.isEmpty(entClsToAuthz);
 
-                        if (hasEntityAccess && hasClassificationsAccess) {
+                        if (ret) {
                             break;
                         }
                     }
@@ -277,11 +281,9 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer {
             }
         }
 
-        boolean ret = hasEntityAccess && hasClassificationsAccess;
-
         if (LOG.isDebugEnabled()) {
             if (!ret) {
-                LOG.debug("hasEntityAccess={}; hasClassificationsAccess={}, classificationsWithNoAccess={}", hasEntityAccess, hasClassificationsAccess, entClsToAuthz);
+                LOG.debug("isAccessAllowed={}; classificationsWithNoAccess={}", ret, entClsToAuthz);
             }
 
             LOG.debug("<== SimpleAtlasAuthorizer.isAccessAllowed({}): {}", request, ret);
@@ -490,6 +492,10 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer {
         return AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA.equals(request.getAction()) ? isMatch(request.getBusinessMetadata(), permission.getBusinessMetadata()) : true;
     }
 
+    private boolean isClassificationMatch(AtlasEntityAccessRequest request, AtlasEntityPermission permission) {
+        return (CLASSIFICATION_PRIVILEGES.contains(request.getAction()) && request.getClassification() != null) ? isMatch(request.getClassification().getTypeName(), permission.getClassifications()) : true;
+    }
+
     private void filterTypes(AtlasAccessRequest request, List<? extends AtlasBaseTypeDef> typeDefs)throws AtlasAuthorizationException {
         if (typeDefs != null) {
             for (ListIterator<? extends AtlasBaseTypeDef> iter = typeDefs.listIterator(); iter.hasNext();) {
diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java
index d191128..ee13233 100644
--- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java
+++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java
@@ -205,29 +205,31 @@ public class AtlasSimpleAuthzPolicy implements Serializable {
     public static class AtlasEntityPermission implements Serializable {
         private static final long serialVersionUID = 1L;
 
-        private List<String> privileges;       // name of AtlasPrivilege enum, wildcards supported
-        private List<String> entityTypes;      // name of entity-type, wildcards supported
-        private List<String> entityIds;        // value of entity-unique attribute, wildcards supported
-        private List<String> classifications;  // name of classification-type, wildcards supported
-        private List<String> labels;           // labels, wildcards supported
-        private List<String> businessMetadata; // name of business-metadata, wildcards supported
-        private List<String> attributes;       // name of entity-attribute, wildcards supported
+        private List<String> privileges;            // name of AtlasPrivilege enum, wildcards supported
+        private List<String> entityTypes;           // name of entity-type, wildcards supported
+        private List<String> entityIds;             // value of entity-unique attribute, wildcards supported
+        private List<String> entityClassifications; // name of entity classification-type, wildcards supported
+        private List<String> labels;                // labels, wildcards supported
+        private List<String> businessMetadata;      // name of business-metadata, wildcards supported
+        private List<String> attributes;            // name of entity-attribute, wildcards supported
+        private List<String> classifications;       // name of classification-type, wildcards supported
 
         public AtlasEntityPermission() {
         }
 
         public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> attributes) {
-            this(privileges, entityTypes, entityIds, classifications, attributes, null, null);
+            this(privileges, entityTypes, entityIds, classifications, attributes, null, null, null);
         }
 
-        public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> labels, List<String> businessMetadata, List<String> attributes) {
-            this.privileges       = privileges;
-            this.entityTypes      = entityTypes;
-            this.entityIds        = entityIds;
-            this.classifications  = classifications;
-            this.labels           = labels;
-            this.businessMetadata = businessMetadata;
-            this.attributes       = attributes;
+        public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> entityClassifications, List<String> labels, List<String> businessMetadata, List<String> attributes, List<String> classifications) {
+            this.privileges            = privileges;
+            this.entityTypes           = entityTypes;
+            this.entityIds             = entityIds;
+            this.entityClassifications = entityClassifications;
+            this.labels                = labels;
+            this.businessMetadata      = businessMetadata;
+            this.attributes            = attributes;
+            this.classifications       = classifications;
         }
 
         public List<String> getPrivileges() {
@@ -254,12 +256,12 @@ public class AtlasSimpleAuthzPolicy implements Serializable {
             this.entityIds = entityIds;
         }
 
-        public List<String> getClassifications() {
-            return classifications;
+        public List<String> getEntityClassifications() {
+            return entityClassifications;
         }
 
-        public void setClassifications(List<String> classifications) {
-            this.classifications = classifications;
+        public void setEntityClassifications(List<String> entityClassifications) {
+            this.entityClassifications = entityClassifications;
         }
 
         public List<String> getLabels() {
@@ -285,6 +287,14 @@ public class AtlasSimpleAuthzPolicy implements Serializable {
         public void setAttributes(List<String> attributes) {
             this.attributes = attributes;
         }
+
+        public List<String> getClassifications() {
+            return classifications;
+        }
+
+        public void setClassifications(List<String> classifications) {
+            this.classifications = classifications;
+        }
     }
 
 
diff --git a/authorization/src/main/resources/atlas-simple-authz-policy.json b/authorization/src/main/resources/atlas-simple-authz-policy.json
index 6b20012..bd9d5ed 100644
--- a/authorization/src/main/resources/atlas-simple-authz-policy.json
+++ b/authorization/src/main/resources/atlas-simple-authz-policy.json
@@ -15,12 +15,14 @@
       ],
       "entityPermissions": [
         {
-          "privileges":      [ ".*" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ],
-          "labels":          [ ".*" ],
-          "namespaces":      [ ".*" ]
+          "privileges":            [ ".*" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
         }
       ],
       "relationshipPermissions": [
@@ -40,12 +42,14 @@
     "DATA_SCIENTIST": {
       "entityPermissions": [
         {
-          "privileges":      [ "entity-read", "entity-read-classification" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ],
-          "labels":          [ ".*" ],
-          "businessMetadata":      [ ".*" ]
+          "privileges":            [ "entity-read", "entity-read-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
         }
       ]
     },
@@ -53,12 +57,14 @@
     "DATA_STEWARD": {
       "entityPermissions": [
         {
-          "privileges":      [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ],
-          "labels":          [ ".*" ],
-          "businessMetadata":      [ ".*" ]
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
         }
       ],
       "relationshipPermissions": [
diff --git a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
index 7083b82..8d38ebe 100644
--- a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
+++ b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
@@ -17,6 +17,8 @@
 package org.apache.atlas.authorize.simple;
 
 import org.apache.atlas.authorize.*;
+import org.apache.atlas.model.instance.AtlasClassification;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterClass;
@@ -24,14 +26,48 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import org.testng.AssertJUnit;
 
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 public class AtlasSimpleAuthorizerTest {
     private static Logger LOG = LoggerFactory.getLogger(AtlasSimpleAuthorizerTest.class);
 
-    private static final String USER_DATA_SCIENTIST = "dataScientist1";
-    private static final String USER_DATA_STEWARD   = "dataSteward1";
-
+    private static final String USER_ADMIN            = "admin";
+    private static final String USER_DATA_SCIENTIST   = "dataScientist";
+    private static final String USER_DATA_STEWARD     = "dataSteward";
+    private static final String USER_DATA_STEWARD_EX  = "dataStewardEx";
+    private static final String USER_FINANCE          = "finance";
+    private static final String USER_FINANCE_PII      = "financePII";
+    private static final String USER_IN_ADMIN_GROUP   = "admin-group-user";
+    private static final String USER_IN_UNKNOWN_GROUP = "unknown-group-user";
+
+    private static final Map<String, Set<String>> USER_GROUPS = new HashMap<String, Set<String>>() {{
+                                                                        put(USER_ADMIN, Collections.singleton("ROLE_ADMIN"));
+                                                                        put(USER_DATA_STEWARD, Collections.emptySet());
+                                                                        put(USER_DATA_SCIENTIST, Collections.emptySet());
+                                                                        put(USER_DATA_STEWARD_EX, Collections.singleton("DATA_STEWARD_EX"));
+                                                                        put(USER_FINANCE, Collections.singleton("FINANCE"));
+                                                                        put(USER_FINANCE_PII, Collections.singleton("FINANCE_PII"));
+                                                                        put(USER_IN_ADMIN_GROUP, Collections.singleton("ROLE_ADMIN"));
+                                                                        put(USER_IN_UNKNOWN_GROUP, Collections.singleton("UNKNOWN_GROUP"));
+                                                                    }};
+
+    private static final List<AtlasPrivilege> ENTITY_PRIVILEGES = Arrays.asList(AtlasPrivilege.ENTITY_CREATE,
+                                                                                AtlasPrivilege.ENTITY_UPDATE,
+                                                                                AtlasPrivilege.ENTITY_READ,
+                                                                                AtlasPrivilege.ENTITY_ADD_CLASSIFICATION,
+                                                                                AtlasPrivilege.ENTITY_UPDATE_CLASSIFICATION,
+                                                                                AtlasPrivilege.ENTITY_REMOVE_CLASSIFICATION,
+                                                                                AtlasPrivilege.ENTITY_READ_CLASSIFICATION,
+                                                                                AtlasPrivilege.ENTITY_ADD_LABEL,
+                                                                                AtlasPrivilege.ENTITY_REMOVE_LABEL,
+                                                                                AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA);
+
+    private static final List<AtlasPrivilege> LABEL_PRIVILEGES = Arrays.asList(AtlasPrivilege.ENTITY_ADD_LABEL, AtlasPrivilege.ENTITY_REMOVE_LABEL);
 
     private String          originalConf;
     private AtlasAuthorizer authorizer;
@@ -59,15 +95,34 @@ public class AtlasSimpleAuthorizerTest {
     }
 
     @Test(enabled = true)
-    public void testAccessAllowedForUserAndGroup() {
+    public void testAllAllowedForAdminUser() {
         try {
-            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
+            for (AtlasPrivilege privilege : AtlasPrivilege.values()) {
+                AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege);
+
+                setUser(request, USER_ADMIN);
+
+                boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+
+                AssertJUnit.assertEquals(privilege.name() + " should have been allowed for user " + USER_DATA_SCIENTIST, true, isAccessAllowed);
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+        }
+    }
+
+    @Test(enabled = true)
+    public void testAddPIIForStewardExUser() {
+        try {
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null , AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, null,  new AtlasClassification("PII"));
 
-            request.setUser("admin", Collections.singleton("ROLE_ADMIN"));
+            setUser(request, USER_DATA_STEWARD_EX);
 
             boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals(true, isAccessAllowed);
+            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed to add PII", true, isAccessAllowed);
         } catch (Exception e) {
             LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
@@ -76,16 +131,20 @@ public class AtlasSimpleAuthorizerTest {
     }
 
     @Test(enabled = true)
-    public void testAccessAllowedForGroup() {
+    public void testAddClassificationOnEntityWithClassificationForStewardExUser() {
         try {
-            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
 
-            request.setUser("nonmappeduser", Collections.singleton("ROLE_ADMIN"));
+            AtlasEntityHeader entityHeader = new AtlasEntityHeader();
+            entityHeader.setClassifications(Arrays.asList(new AtlasClassification("PII_1"), new AtlasClassification("PII_2")));
+
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, entityHeader, new AtlasClassification("PII"));
+
+            setUser(request, USER_DATA_STEWARD_EX);
 
             boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals(true, isAccessAllowed);
-        } catch (AtlasAuthorizationException e) {
+            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed to add PII", true, isAccessAllowed);
+        } catch (Exception e) {
             LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
             AssertJUnit.fail();
@@ -93,16 +152,20 @@ public class AtlasSimpleAuthorizerTest {
     }
 
     @Test(enabled = true)
-    public void testAccessNotAllowedForUserAndGroup() {
+    public void testAddClassificationOnEntityWithClassificationForStewardExUserShouldFail() {
         try {
-            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
 
-            request.setUser("nonmappeduser", Collections.singleton("GROUP-NOT-IN-POLICYFILE"));
+            AtlasEntityHeader entityHeader = new AtlasEntityHeader();
+            entityHeader.setClassifications(Arrays.asList(new AtlasClassification("TAG1"), new AtlasClassification("TAG2")));
+
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, entityHeader, new AtlasClassification("PII"));
+
+            setUser(request, USER_DATA_STEWARD_EX);
 
             boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals(false, isAccessAllowed);
-        } catch (AtlasAuthorizationException e) {
+            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have not been allowed to add PII on entity with TAG1,TAG2 classification ", false, isAccessAllowed);
+        } catch (Exception e) {
             LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
             AssertJUnit.fail();
@@ -110,38 +173,149 @@ public class AtlasSimpleAuthorizerTest {
     }
 
     @Test(enabled = true)
-    public void testLabels() {
+    public void testAddPIIForStewardUser() {
+        try {
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null , AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, null,  new AtlasClassification("PII"));
+
+            setUser(request, USER_DATA_STEWARD);
+
+            boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+
+            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should not have been allowed to add PII", false, isAccessAllowed);
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+        }
+    }
+
+    @Test(enabled = true)
+    public void testFinancePIIEntityAccessForFinancePIIUser() {
+        try {
+            AtlasEntityHeader entity = new AtlasEntityHeader() {{
+                                                setClassifications(Arrays.asList(new AtlasClassification("FINANCE"), new AtlasClassification("PII")));
+                                            }};
+
+            for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) {
+                AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("PII"));
+
+                setUser(request, USER_FINANCE_PII);
+
+                boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+
+                AssertJUnit.assertEquals("user " + USER_FINANCE_PII + " should have been allowed " + privilege + " on entity with FINANCE & PII", true, isAccessAllowed);
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+        }
+    }
+
+    @Test(enabled = true)
+    public void testFinancePIIEntityAccessForFinanceUser() {
+        try {
+            AtlasEntityHeader entity = new AtlasEntityHeader() {{
+                                                setClassifications(Arrays.asList(new AtlasClassification("FINANCE"), new AtlasClassification("PII")));
+                                            }};
+
+            for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) {
+                AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("PII"));
+
+                setUser(request, USER_FINANCE);
+
+                boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+
+                AssertJUnit.assertEquals("user " + USER_FINANCE + " should not have been allowed " + privilege + " on entity with FINANCE & PII", false, isAccessAllowed);
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+        }
+    }
+
+    @Test(enabled = true)
+    public void testFinanceEntityAccess() {
+        try {
+            AtlasEntityHeader entity = new AtlasEntityHeader() {{
+                setClassifications(Arrays.asList(new AtlasClassification("FINANCE")));
+            }};
+
+            for (String userName : Arrays.asList(USER_FINANCE_PII, USER_FINANCE)) {
+                for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) {
+                    AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("FINANCE"));
+
+                    setUser(request, userName);
+
+                    boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+
+                    AssertJUnit.assertEquals("user " + userName + " should have been allowed " + privilege + " on entity with FINANCE", true, isAccessAllowed);
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+        }
+    }
+
+    @Test(enabled = true)
+    public void testAccessForUserInAdminGroup() {
         try {
-            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_LABEL);
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
 
-            request.setUser(USER_DATA_SCIENTIST, Collections.emptySet());
+            setUser(request, USER_IN_ADMIN_GROUP);
 
             boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to add label", false, isAccessAllowed);
+            AssertJUnit.assertEquals("user " + USER_IN_ADMIN_GROUP + " should have been allowed " + AtlasPrivilege.ENTITY_UPDATE, true, isAccessAllowed);
+        } catch (AtlasAuthorizationException e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
+            AssertJUnit.fail();
+        }
+    }
 
-            request.setUser(USER_DATA_STEWARD, Collections.emptySet());
+    @Test(enabled = true)
+    public void testAccessForUserInUnknownGroup() {
+        try {
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
+
+            setUser(request, USER_IN_UNKNOWN_GROUP);
 
-            isAccessAllowed = authorizer.isAccessAllowed(request);
+            boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to add label", true, isAccessAllowed);
+            AssertJUnit.assertEquals("user " + USER_IN_UNKNOWN_GROUP + " should not have been allowed " + AtlasPrivilege.ENTITY_UPDATE, false, isAccessAllowed);
+        } catch (AtlasAuthorizationException e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
+            AssertJUnit.fail();
+        }
+    }
 
-            request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_REMOVE_LABEL);
+    @Test(enabled = true)
+    public void testLabels() {
+        try {
+            for (AtlasPrivilege privilege : LABEL_PRIVILEGES) {
+                for (String userName : Arrays.asList(USER_DATA_SCIENTIST, USER_DATA_STEWARD)) {
+                    AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege);
 
-            request.setUser(USER_DATA_SCIENTIST, Collections.emptySet());
+                    setUser(request, userName);
 
-            isAccessAllowed = authorizer.isAccessAllowed(request);
+                    boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to remove label", false, isAccessAllowed);
+                    AssertJUnit.assertEquals("user " + userName + " should not have been allowed " + privilege, false, isAccessAllowed);
+                }
 
+                AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege);
 
-            request.setUser(USER_DATA_STEWARD, Collections.emptySet());
+                setUser(request, USER_DATA_STEWARD_EX);
 
-            isAccessAllowed = authorizer.isAccessAllowed(request);
+                boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to remove label", true, isAccessAllowed);
+                AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed " + privilege, true, isAccessAllowed);
+            }
         } catch (AtlasAuthorizationException e) {
             LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
@@ -152,23 +326,33 @@ public class AtlasSimpleAuthorizerTest {
     @Test(enabled = true)
     public void testBusinessMetadata() {
         try {
-            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA);
+            for (String userName : Arrays.asList(USER_DATA_SCIENTIST, USER_DATA_STEWARD)) {
+                AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA);
 
-            request.setUser(USER_DATA_SCIENTIST, Collections.emptySet());
+                setUser(request, userName);
 
-            boolean isAccessAllowed = authorizer.isAccessAllowed(request);
+                boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to update business-metadata", false, isAccessAllowed);
+                AssertJUnit.assertEquals("user " + userName + " should not have been allowed " + AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA, false, isAccessAllowed);
+            }
 
-            request.setUser(USER_DATA_STEWARD, Collections.emptySet());
+            AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA);
+
+            setUser(request, USER_DATA_STEWARD_EX);
 
-            isAccessAllowed = authorizer.isAccessAllowed(request);
+            boolean isAccessAllowed = authorizer.isAccessAllowed(request);
 
-            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to update business-metadata", true, isAccessAllowed);
+            AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed " + AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA, true, isAccessAllowed);
         } catch (AtlasAuthorizationException e) {
             LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
 
             AssertJUnit.fail();
         }
     }
+
+    private void setUser(AtlasAccessRequest request, String userName) {
+        Set<String> userGroups = USER_GROUPS.get(userName);
+
+        request.setUser(userName, userGroups != null ? userGroups : Collections.emptySet());
+    }
 }
diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json b/authorization/src/test/resources/atlas-simple-authz-policy.json
index 9db6505..cada904 100644
--- a/authorization/src/test/resources/atlas-simple-authz-policy.json
+++ b/authorization/src/test/resources/atlas-simple-authz-policy.json
@@ -9,10 +9,11 @@
 
       "entityPermissions": [
         {
-          "privileges":      [ ".*" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ]
+          "privileges":            [ ".*" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "classifications":       [ ".*" ],
+          "entityClassifications": [ ".*" ]
         }
       ],
 
@@ -53,12 +54,77 @@
     "DATA_STEWARD": {
       "entityPermissions": [
         {
-          "privileges":       [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
-          "entityTypes":      [ ".*" ],
-          "entityIds":        [ ".*" ],
-          "classifications":  [ ".*" ],
-          "labels":           [ ".*" ],
-          "businessMetadata": [ ".*" ]
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
+        }
+      ]
+    },
+
+    "FINANCE": {
+      "entityPermissions": [
+        {
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ "FINANCE" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ]
+        },
+        {
+          "privileges":            [ "entity-add-classification", "entity-update-classification", "entity-remove-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ "FINANCE" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ "FINANCE" ]
+        }
+      ]
+    },
+
+    "FINANCE_PII": {
+      "entityPermissions": [
+        {
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ "FINANCE", "PII" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ]
+        },
+        {
+          "privileges":            [ "entity-add-classification", "entity-update-classification", "entity-remove-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ "FINANCE", "PII" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ "FINANCE", "PII" ]
+        }
+      ]
+    },
+
+    "DATA_STEWARD_EX": {
+      "entityPermissions": [
+        {
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ "PII.*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ "PII.*" ]
         }
       ]
     }
@@ -75,6 +141,10 @@
     "ROLE_ADMIN":      [ "ROLE_ADMIN" ],
     "hadoop":          [ "DATA_STEWARD" ],
     "DATA_STEWARD":    [ "DATA_STEWARD" ],
-    "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ]
+    "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ],
+    "FINANCE":         [ "FINANCE" ],
+    "FINANCE_PII":     [ "FINANCE_PII" ],
+    "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ],
+    "DATA_STEWARD_EX": [ "DATA_STEWARD_EX" ]
   }
 }
diff --git a/distro/src/conf/atlas-simple-authz-policy.json b/distro/src/conf/atlas-simple-authz-policy.json
index 8a3ce60..a5761cc 100644
--- a/distro/src/conf/atlas-simple-authz-policy.json
+++ b/distro/src/conf/atlas-simple-authz-policy.json
@@ -15,13 +15,14 @@
       ],
       "entityPermissions": [
         {
-          "privileges":      [ ".*" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ],
-          "labels" : [ ".*" ],
-          "businessMetadata" : [ ".*" ],
-          "attributes" :[ ".*" ]
+          "privileges":            [ ".*" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
         }
       ],
       "relationshipPermissions": [
@@ -41,10 +42,13 @@
     "DATA_SCIENTIST": {
       "entityPermissions": [
         {
-          "privileges":      [ "entity-read", "entity-read-classification" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ]
+          "privileges":            [ "entity-read", "entity-read-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ]
         }
       ]
     },
@@ -52,10 +56,14 @@
     "DATA_STEWARD": {
       "entityPermissions": [
         {
-          "privileges":      [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ],
-          "entityTypes":     [ ".*" ],
-          "entityIds":       [ ".*" ],
-          "classifications": [ ".*" ]
+          "privileges":            [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ ".*" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ],
+          "classifications":       [ ".*" ]
         }
       ],
       "relationshipPermissions": [