This is an automated email from the ASF dual-hosted git repository.
pinal-shah pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/master by this push:
new f9e482f697 ATLAS-5388: Add topic-scoped authorization for REST
notification POST. (#753)
f9e482f697 is described below
commit f9e482f697d0fafd702f44cb5e63e861e9156b74
Author: UmeshPatil-1 <[email protected]>
AuthorDate: Tue Oct 27 16:33:45 2026 +0530
ATLAS-5388: Add topic-scoped authorization for REST notification POST.
(#753)
---
.../atlas/authorize/AtlasAuthorizationUtils.java | 36 ++++++++++++
.../atlas/authorize/AtlasAuthorizeConstants.java | 25 ++++++++
.../apache/atlas/authorize/AtlasAuthorizer.java | 4 ++
.../atlas/authorize/AtlasNoneAuthorizer.java | 5 ++
.../atlas/authorize/AtlasNotificationRequest.java | 44 +++++++++++++++
.../org/apache/atlas/authorize/AtlasPrivilege.java | 2 +-
.../authorize/simple/AtlasSimpleAuthorizer.java | 53 +++++++++++++++++
.../authorize/simple/AtlasSimpleAuthzPolicy.java | 66 +++++++++++++++++++---
.../main/resources/atlas-simple-authz-policy.json | 18 +++++-
.../AtlasAuthorizationUtilsNotificationTest.java | 58 +++++++++++++++++++
.../simple/AtlasSimpleAuthorizerTest.java | 60 ++++++++++++++++++++
.../test/resources/atlas-simple-authz-policy.json | 16 ++++++
distro/src/conf/atlas-simple-authz-policy.json | 18 +++++-
.../rest/web/rest/NotificationREST.java | 4 +-
14 files changed, 396 insertions(+), 13 deletions(-)
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java
index a1c68b3a39..b40d03b307 100644
---
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java
+++
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java
@@ -80,6 +80,14 @@ public class AtlasAuthorizationUtils {
}
}
+ public static void verifyAccess(AtlasNotificationRequest request,
Object... errorMsgParams) throws AtlasBaseException {
+ if (!isAccessAllowed(request)) {
+ String message = (errorMsgParams != null && errorMsgParams.length
> 0) ? StringUtils.join(errorMsgParams) : "";
+
+ throw new AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS,
request.getUser(), message);
+ }
+ }
+
public static void scrubSearchResults(AtlasSearchResultScrubRequest
request) {
String userName = getCurrentUserName();
@@ -231,6 +239,34 @@ public class AtlasAuthorizationUtils {
return ret;
}
+ public static boolean isAccessAllowed(AtlasNotificationRequest request) {
+ MetricRecorder metric =
RequestContext.get().startMetricRecord("isAccessAllowed");
+
+ boolean ret = false;
+ String userName = getCurrentUserName();
+
+ if (request == null || StringUtils.isBlank(request.getTopicName())) {
+ ret = false;
+ } else if (StringUtils.isNotEmpty(userName)) {
+ try {
+ AtlasAuthorizer authorizer =
AtlasAuthorizerFactory.getAtlasAuthorizer();
+
+ request.setUser(userName, getCurrentUserGroups());
+
request.setClientIPAddress(RequestContext.get().getClientIPAddress());
+
request.setForwardedAddresses(RequestContext.get().getForwardedAddresses());
+
request.setRemoteIPAddress(RequestContext.get().getClientIPAddress());
+
+ ret = authorizer.isAccessAllowed(request);
+ } catch (AtlasAuthorizationException e) {
+ LOG.error("Unable to obtain AtlasAuthorizer", e);
+ }
+ }
+
+ RequestContext.get().endMetricRecord(metric);
+
+ return ret;
+ }
+
public static void filterTypesDef(AtlasTypesDefFilterRequest request) {
MetricRecorder metric =
RequestContext.get().startMetricRecord("filterTypesDef");
String userName = getCurrentUserName();
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizeConstants.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizeConstants.java
new file mode 100644
index 0000000000..8dc4f8d1df
--- /dev/null
+++
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizeConstants.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.atlas.authorize;
+
+public final class AtlasAuthorizeConstants {
+ public static final String NOTIFICATION_TOPIC_RESOURCE_TYPE =
"notification-topic";
+
+ private AtlasAuthorizeConstants() {
+ }
+}
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java
index 845b05f9a6..1af12af87b 100644
---
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java
+++
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java
@@ -65,6 +65,10 @@ public interface AtlasAuthorizer {
return true;
}
+ default boolean isAccessAllowed(AtlasNotificationRequest request) throws
AtlasAuthorizationException {
+ return false;
+ }
+
/**
* scrub search-results to handle entities for which the user doesn't have
access
* @param request
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java
index 86909d9249..971bd4e148 100644
---
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java
+++
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java
@@ -49,6 +49,11 @@ public class AtlasNoneAuthorizer implements AtlasAuthorizer {
return true;
}
+ @Override
+ public boolean isAccessAllowed(AtlasNotificationRequest request) {
+ return true;
+ }
+
@Override
public void scrubSearchResults(AtlasSearchResultScrubRequest request) {
}
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasNotificationRequest.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNotificationRequest.java
new file mode 100644
index 0000000000..f9c0b53a75
--- /dev/null
+++
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNotificationRequest.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.atlas.authorize;
+
+public class AtlasNotificationRequest extends AtlasAccessRequest {
+ private final String topicName;
+
+ public AtlasNotificationRequest(AtlasPrivilege action, String topicName) {
+ super(action);
+
+ this.topicName = topicName;
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public String getResourceType() {
+ return AtlasAuthorizeConstants.NOTIFICATION_TOPIC_RESOURCE_TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return "AtlasNotificationRequest[action=" + getAction() + ",
topicName=" + topicName + ", resourceType=" + getResourceType() +
+ ", accessTime=" + getAccessTime() + ", user=" + getUser() + ",
userGroups=" + getUserGroups() +
+ ", clientIPAddress=" + getClientIPAddress() + ",
forwardedAddresses=" + getForwardedAddresses() +
+ ", remoteIPAddress=" + getRemoteIPAddress() + "]";
+ }
+}
diff --git
a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java
b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java
index 68402fd507..e02d89b708 100644
--- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java
+++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java
@@ -48,7 +48,7 @@ public enum AtlasPrivilege {
ADMIN_AUDITS("admin-audits"),
- SERVICE_NOTIFICATION_POST("service-notification-post");
+ POST_NOTIFICATION("post-notification");
private final String type;
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 2de553b047..98c545a65b 100755
---
a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java
+++
b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java
@@ -24,6 +24,7 @@ import org.apache.atlas.authorize.AtlasAccessRequest;
import org.apache.atlas.authorize.AtlasAdminAccessRequest;
import org.apache.atlas.authorize.AtlasAuthorizer;
import org.apache.atlas.authorize.AtlasEntityAccessRequest;
+import org.apache.atlas.authorize.AtlasNotificationRequest;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.authorize.AtlasRelationshipAccessRequest;
import org.apache.atlas.authorize.AtlasSearchResultScrubRequest;
@@ -32,6 +33,7 @@ import org.apache.atlas.authorize.AtlasTypesDefFilterRequest;
import
org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasAdminPermission;
import org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasAuthzRole;
import
org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasEntityPermission;
+import
org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasNotificationPermission;
import
org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasRelationshipPermission;
import
org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.AtlasTypePermission;
import org.apache.atlas.model.discovery.AtlasSearchResult;
@@ -253,6 +255,45 @@ public final class AtlasSimpleAuthorizer implements
AtlasAuthorizer {
return hasEnd1EntityAccess && hasEnd2EntityAccess;
}
+ @Override
+ public boolean isAccessAllowed(AtlasNotificationRequest request) {
+ LOG.debug("==> SimpleAtlasAuthorizer.isAccessAllowed({})", request);
+
+ if (request == null || StringUtils.isBlank(request.getTopicName())) {
+ LOG.debug("<== SimpleAtlasAuthorizer.isAccessAllowed({}): false
(missing topic)", request);
+
+ return false;
+ }
+
+ boolean ret = false;
+ Set<String> roles = getRoles(request.getUser(),
request.getUserGroups());
+
+ for (String role : roles) {
+ List<AtlasNotificationPermission> permissions =
getNotificationPermissionsForRole(role);
+
+ if (permissions != null) {
+ final String action = request.getAction() != null ?
request.getAction().getType() : null;
+ final String topicName = request.getTopicName();
+
+ for (AtlasNotificationPermission permission : permissions) {
+ if (isMatch(action, permission.getPrivileges()) &&
isMatch(topicName, permission.getTopicNames())) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ if (ret) {
+ break;
+ }
+ }
+
+ LOG.debug("<== SimpleAtlasAuthorizer.isAccessAllowed({}): {}",
request, ret);
+
+ return ret;
+ }
+
@Override
public void scrubSearchResults(AtlasSearchResultScrubRequest request) {
LOG.debug("==> SimpleAtlasAuthorizer.scrubSearchResults({})", request);
@@ -370,6 +411,18 @@ public final class AtlasSimpleAuthorizer implements
AtlasAuthorizer {
return ret;
}
+ private List<AtlasNotificationPermission>
getNotificationPermissionsForRole(String roleName) {
+ List<AtlasNotificationPermission> ret = null;
+
+ if (authzPolicy != null && roleName != null) {
+ AtlasAuthzRole role = authzPolicy.getRoles().get(roleName);
+
+ ret = role != null ? role.getNotificationPermissions() : null;
+ }
+
+ return ret;
+ }
+
private boolean isMatch(String value, List<String> patterns) {
boolean ret = value == null;
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 b4899a8bdf..88dc5f330c 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
@@ -76,19 +76,25 @@ public class AtlasSimpleAuthzPolicy implements Serializable
{
public static class AtlasAuthzRole implements Serializable {
private static final long serialVersionUID = 1L;
- private List<AtlasAdminPermission> adminPermissions;
- private List<AtlasTypePermission> typePermissions;
- private List<AtlasEntityPermission> entityPermissions;
- private List<AtlasRelationshipPermission> relationshipPermissions;
+ private List<AtlasAdminPermission> adminPermissions;
+ private List<AtlasTypePermission> typePermissions;
+ private List<AtlasEntityPermission> entityPermissions;
+ private List<AtlasRelationshipPermission> relationshipPermissions;
+ private List<AtlasNotificationPermission> notificationPermissions;
public AtlasAuthzRole() {
}
public AtlasAuthzRole(List<AtlasAdminPermission> adminPermissions,
List<AtlasTypePermission> typePermissions, List<AtlasEntityPermission>
entityPermissions, List<AtlasRelationshipPermission> relationshipPermissions) {
- this.adminPermissions = adminPermissions;
- this.typePermissions = typePermissions;
- this.entityPermissions = entityPermissions;
- this.relationshipPermissions = relationshipPermissions;
+ this(adminPermissions, typePermissions, entityPermissions,
relationshipPermissions, null);
+ }
+
+ public AtlasAuthzRole(List<AtlasAdminPermission> adminPermissions,
List<AtlasTypePermission> typePermissions, List<AtlasEntityPermission>
entityPermissions, List<AtlasRelationshipPermission> relationshipPermissions,
List<AtlasNotificationPermission> notificationPermissions) {
+ this.adminPermissions = adminPermissions;
+ this.typePermissions = typePermissions;
+ this.entityPermissions = entityPermissions;
+ this.relationshipPermissions = relationshipPermissions;
+ this.notificationPermissions = notificationPermissions;
}
public List<AtlasAdminPermission> getAdminPermissions() {
@@ -122,6 +128,14 @@ public class AtlasSimpleAuthzPolicy implements
Serializable {
public void
setRelationshipPermissions(List<AtlasRelationshipPermission>
relationshipPermissions) {
this.relationshipPermissions = relationshipPermissions;
}
+
+ public List<AtlasNotificationPermission> getNotificationPermissions() {
+ return notificationPermissions;
+ }
+
+ public void
setNotificationPermissions(List<AtlasNotificationPermission>
notificationPermissions) {
+ this.notificationPermissions = notificationPermissions;
+ }
}
@JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility =
PUBLIC_ONLY, fieldVisibility = NONE)
@@ -391,4 +405,40 @@ public class AtlasSimpleAuthzPolicy implements
Serializable {
this.end2EntityClassification = end2EntityClassification;
}
}
+
+ @JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility =
PUBLIC_ONLY, fieldVisibility = NONE)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ @XmlRootElement
+ @XmlAccessorType(XmlAccessType.PROPERTY)
+ public static class AtlasNotificationPermission implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private List<String> privileges;
+ private List<String> topicNames;
+
+ public AtlasNotificationPermission() {
+ }
+
+ public AtlasNotificationPermission(List<String> privileges,
List<String> topicNames) {
+ this.privileges = privileges;
+ this.topicNames = topicNames;
+ }
+
+ public List<String> getPrivileges() {
+ return privileges;
+ }
+
+ public void setPrivileges(List<String> privileges) {
+ this.privileges = privileges;
+ }
+
+ public List<String> getTopicNames() {
+ return topicNames;
+ }
+
+ public void setTopicNames(List<String> topicNames) {
+ this.topicNames = topicNames;
+ }
+ }
}
diff --git a/authorization/src/main/resources/atlas-simple-authz-policy.json
b/authorization/src/main/resources/atlas-simple-authz-policy.json
index bd9d5ed3cc..38b1ddf562 100644
--- a/authorization/src/main/resources/atlas-simple-authz-policy.json
+++ b/authorization/src/main/resources/atlas-simple-authz-policy.json
@@ -36,6 +36,21 @@
"end2EntityId": [ ".*" ],
"end2EntityClassification": [ ".*" ]
}
+ ],
+ "notificationPermissions": [
+ {
+ "privileges": [ ".*" ],
+ "topicNames": [ ".*" ]
+ }
+ ]
+ },
+
+ "HIVE_HOOK_SERVICE": {
+ "notificationPermissions": [
+ {
+ "privileges": [ "post-notification" ],
+ "topicNames": [ "ATLAS_HOOK" ]
+ }
]
},
@@ -84,7 +99,8 @@
"userRoles": {
"admin": [ "ROLE_ADMIN" ],
- "rangertagsync": [ "DATA_SCIENTIST" ]
+ "rangertagsync": [ "DATA_SCIENTIST" ],
+ "hivehook": [ "HIVE_HOOK_SERVICE" ]
},
"groupRoles": {
diff --git
a/authorization/src/test/java/org/apache/atlas/authorize/AtlasAuthorizationUtilsNotificationTest.java
b/authorization/src/test/java/org/apache/atlas/authorize/AtlasAuthorizationUtilsNotificationTest.java
new file mode 100644
index 0000000000..db1cab829f
--- /dev/null
+++
b/authorization/src/test/java/org/apache/atlas/authorize/AtlasAuthorizationUtilsNotificationTest.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.atlas.authorize;
+
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+public class AtlasAuthorizationUtilsNotificationTest {
+ private static final String TOPIC_ATLAS_HOOK = "ATLAS_HOOK";
+
+ @AfterMethod
+ public void clearSecurityContext() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void testNotificationAccessDeniedWhenTopicNull() {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, null);
+
+ AssertJUnit.assertFalse("null topic must be denied at authorization
utils layer",
+ AtlasAuthorizationUtils.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testNotificationAccessDeniedWhenTopicBlank() {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, " ");
+
+ AssertJUnit.assertFalse("blank topic must be denied at authorization
utils layer",
+ AtlasAuthorizationUtils.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testNotificationAccessDeniedWhenNoAuthenticatedUser() {
+ SecurityContextHolder.clearContext();
+
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, TOPIC_ATLAS_HOOK);
+
+ AssertJUnit.assertFalse("empty username must fail closed for
notification ingress",
+ AtlasAuthorizationUtils.isAccessAllowed(request));
+ }
+}
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 d61ae7afca..7f00e4df1c 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
@@ -21,6 +21,7 @@ import org.apache.atlas.authorize.AtlasAuthorizationException;
import org.apache.atlas.authorize.AtlasAuthorizer;
import org.apache.atlas.authorize.AtlasAuthorizerFactory;
import org.apache.atlas.authorize.AtlasEntityAccessRequest;
+import org.apache.atlas.authorize.AtlasNotificationRequest;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasEntityHeader;
@@ -50,6 +51,10 @@ public class AtlasSimpleAuthorizerTest {
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 String USER_HIVE_HOOK = "hivehook";
+
+ private static final String TOPIC_ATLAS_HOOK = "ATLAS_HOOK";
+ private static final String TOPIC_ATLAS_ENTITIES = "ATLAS_ENTITIES";
private static final Map<String, Set<String>> USER_GROUPS = new
HashMap<>();
private static final List<AtlasPrivilege> ENTITY_PRIVILEGES = new
ArrayList<>();
@@ -309,6 +314,60 @@ public class AtlasSimpleAuthorizerTest {
}
}
+ @Test
+ public void testPostNotificationAllowedForAdminUser() throws
AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, TOPIC_ATLAS_HOOK);
+
+ setUser(request, USER_ADMIN);
+
+ AssertJUnit.assertTrue("admin should be allowed to post notification",
authorizer.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testPostNotificationDeniedForDataScientistUser() throws
AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, TOPIC_ATLAS_HOOK);
+
+ setUser(request, USER_DATA_SCIENTIST);
+
+ AssertJUnit.assertFalse("data scientist should be denied to post
notification", authorizer.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testPostNotificationAllowedForTopicSpecificRole() throws
AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, TOPIC_ATLAS_HOOK);
+
+ setUser(request, USER_HIVE_HOOK);
+
+ AssertJUnit.assertTrue("hivehook should be allowed to post to
ATLAS_HOOK", authorizer.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testPostNotificationDeniedForTopicSpecificRoleOnOtherTopic()
throws AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION,
TOPIC_ATLAS_ENTITIES);
+
+ setUser(request, USER_HIVE_HOOK);
+
+ AssertJUnit.assertFalse("hivehook should be denied to post to
ATLAS_ENTITIES", authorizer.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testPostNotificationDeniedForNullTopic() throws
AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, null);
+
+ setUser(request, USER_ADMIN);
+
+ AssertJUnit.assertFalse("null topic must not bypass topic scoping",
authorizer.isAccessAllowed(request));
+ }
+
+ @Test
+ public void testPostNotificationDeniedForBlankTopic() throws
AtlasAuthorizationException {
+ AtlasNotificationRequest request = new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, " ");
+
+ setUser(request, USER_ADMIN);
+
+ AssertJUnit.assertFalse("blank topic must not bypass topic scoping",
authorizer.isAccessAllowed(request));
+ }
+
@Test
public void testBusinessMetadata() {
try {
@@ -351,6 +410,7 @@ public class AtlasSimpleAuthorizerTest {
USER_GROUPS.put(USER_FINANCE_PII,
Collections.singleton("FINANCE_PII"));
USER_GROUPS.put(USER_IN_ADMIN_GROUP,
Collections.singleton("ROLE_ADMIN"));
USER_GROUPS.put(USER_IN_UNKNOWN_GROUP,
Collections.singleton("UNKNOWN_GROUP"));
+ USER_GROUPS.put(USER_HIVE_HOOK, Collections.emptySet());
ENTITY_PRIVILEGES.add(AtlasPrivilege.ENTITY_CREATE);
ENTITY_PRIVILEGES.add(AtlasPrivilege.ENTITY_UPDATE);
diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json
b/authorization/src/test/resources/atlas-simple-authz-policy.json
index cada904470..376cea1380 100644
--- a/authorization/src/test/resources/atlas-simple-authz-policy.json
+++ b/authorization/src/test/resources/atlas-simple-authz-policy.json
@@ -35,6 +35,21 @@
"endTwoEntityId": [ ".*" ],
"endTwoEntityClassification": [ ".*" ]
}
+ ],
+ "notificationPermissions": [
+ {
+ "privileges": [ ".*" ],
+ "topicNames": [ ".*" ]
+ }
+ ]
+ },
+
+ "HIVE_HOOK_SERVICE": {
+ "notificationPermissions": [
+ {
+ "privileges": [ "post-notification" ],
+ "topicNames": [ "ATLAS_HOOK" ]
+ }
]
},
@@ -133,6 +148,7 @@
"userRoles": {
"admin": [ "ROLE_ADMIN" ],
"rangertagsync": [ "DATA_SCIENTIST" ],
+ "hivehook": [ "HIVE_HOOK_SERVICE" ],
"dataScientist1": [ "DATA_SCIENTIST"],
"dataSteward1": [ "DATA_STEWARD"]
},
diff --git a/distro/src/conf/atlas-simple-authz-policy.json
b/distro/src/conf/atlas-simple-authz-policy.json
index a5761cc0e9..1d8e9ef1df 100644
--- a/distro/src/conf/atlas-simple-authz-policy.json
+++ b/distro/src/conf/atlas-simple-authz-policy.json
@@ -36,6 +36,21 @@
"end2EntityId": [ ".*" ],
"end2EntityClassification": [ ".*" ]
}
+ ],
+ "notificationPermissions": [
+ {
+ "privileges": [ ".*" ],
+ "topicNames": [ ".*" ]
+ }
+ ]
+ },
+
+ "HIVE_HOOK_SERVICE": {
+ "notificationPermissions": [
+ {
+ "privileges": [ "post-notification" ],
+ "topicNames": [ "ATLAS_HOOK" ]
+ }
]
},
@@ -83,7 +98,8 @@
"userRoles": {
"admin": [ "ROLE_ADMIN" ],
- "rangertagsync": [ "DATA_SCIENTIST" ]
+ "rangertagsync": [ "DATA_SCIENTIST" ],
+ "hivehook": [ "HIVE_HOOK_SERVICE" ]
},
"groupRoles": {
diff --git
a/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/web/rest/NotificationREST.java
b/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/web/rest/NotificationREST.java
index bbecba3a63..ca9618ad09 100644
---
a/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/web/rest/NotificationREST.java
+++
b/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/web/rest/NotificationREST.java
@@ -21,8 +21,8 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.atlas.AtlasConfiguration;
import org.apache.atlas.AtlasErrorCode;
-import org.apache.atlas.authorize.AtlasAdminAccessRequest;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
+import org.apache.atlas.authorize.AtlasNotificationRequest;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.hook.AtlasHook;
@@ -91,7 +91,7 @@ public class NotificationREST {
public void handleNotifications(@PathParam("topicName") String topicName,
@Context HttpServletRequest request) throws AtlasBaseException, IOException {
LOG.debug("Handling notifications for topic {}", topicName);
- AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.SERVICE_NOTIFICATION_POST), "post on
rest notification service");
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasNotificationRequest(AtlasPrivilege.POST_NOTIFICATION, topicName), "post on
notification topic ", topicName);
if (!TOPICS.contains(topicName)) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_TOPIC_NAME,
topicName);