Commit afbc6975 by nixonrodrigues Committed by Madhan Neethiraj

ATLAS-2459: Authorization enhancements to support instance level access controls

parent be9b39bf
......@@ -115,10 +115,13 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
\ No newline at end of file
......@@ -115,10 +115,13 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
\ No newline at end of file
......@@ -115,10 +115,13 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
\ No newline at end of file
......@@ -115,10 +115,13 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
\ No newline at end of file
......@@ -117,10 +117,13 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
\ No newline at end of file
......@@ -36,10 +36,20 @@
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-intg</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
......
......@@ -17,94 +17,57 @@
*/
package org.apache.atlas.authorize;
import org.apache.atlas.authorize.simple.AtlasAuthorizationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Set;
public class AtlasAccessRequest {
private static Logger LOG = LoggerFactory.getLogger(AtlasAccessRequest.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
private Set<AtlasResourceTypes> resourceType = null;
private String resource = null;
private AtlasActionTypes action = null;
private String user = null;
private Set<String> userGroups = null;
private Date accessTime = null;
private String clientIPAddress = null;
public AtlasAccessRequest(HttpServletRequest request, String user, Set<String> userGroups) {
// Spring Security 4 Change => request.getServletPath() -> request.getPathInfo()
this(AtlasAuthorizationUtils.getAtlasResourceType(request.getPathInfo()), "*", AtlasAuthorizationUtils
.getAtlasAction(request.getMethod(),request.getPathInfo()), user, userGroups,AtlasAuthorizationUtils.getRequestIpAddress(request));
}
public AtlasAccessRequest(Set<AtlasResourceTypes> resourceType, String resource, AtlasActionTypes action,
String user, Set<String> userGroups, String clientIPAddress) {
if (isDebugEnabled) {
LOG.debug("==> AtlasAccessRequestImpl-- Initializing AtlasAccessRequest");
}
setResource(resource);
setAction(action);
setUser(user);
setUserGroups(userGroups);
setResourceType(resourceType);
// set remaining fields to default value
setAccessTime(null);
setClientIPAddress(clientIPAddress);
}
private final AtlasPrivilege action;
private final Date accessTime;
private String user = null;
private Set<String> userGroups = null;
private String clientIPAddress = null;
public Set<AtlasResourceTypes> getResourceTypes() {
return resourceType;
}
public void setResourceType(Set<AtlasResourceTypes> resourceType) {
this.resourceType = resourceType;
protected AtlasAccessRequest(AtlasPrivilege action) {
this(action, null, null, new Date(), null);
}
public String getResource() {
return resource;
protected AtlasAccessRequest(AtlasPrivilege action, String user, Set<String> userGroups) {
this(action, user, userGroups, new Date(), null);
}
public void setResource(String resource) {
this.resource = resource;
protected AtlasAccessRequest(AtlasPrivilege action, String user, Set<String> userGroups, Date accessTime, String clientIPAddress) {
this.action = action;
this.user = user;
this.userGroups = userGroups;
this.accessTime = accessTime;
this.clientIPAddress = clientIPAddress;
}
public AtlasActionTypes getAction() {
public AtlasPrivilege getAction() {
return action;
}
public void setAction(AtlasActionTypes action) {
this.action = action;
public Date getAccessTime() {
return accessTime;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public void setUserGroups(Set<String> userGroups) {
this.userGroups = userGroups;
}
public Set<String> getUserGroups() {
return userGroups;
}
public Date getAccessTime() {
return accessTime;
}
public void setAccessTime(Date accessTime) {
this.accessTime = accessTime;
public void setUser(String user, Set<String> userGroups) {
this.user = user;
this.userGroups = userGroups;
}
public String getClientIPAddress() {
......@@ -117,9 +80,7 @@ public class AtlasAccessRequest {
@Override
public String toString() {
return "AtlasAccessRequest [resourceType=" + resourceType + ", resource=" + resource + ", action=" + action
+ ", user=" + user + ", userGroups=" + userGroups + ", accessTime=" + accessTime + ", clientIPAddress="
+ clientIPAddress + "]";
return "AtlasAccessRequest[action=" + action + ", accessTime=" + accessTime + ", user=" + user +
", userGroups=" + userGroups + ", clientIPAddress=" + clientIPAddress + "]";
}
}
......@@ -17,6 +17,22 @@
*/
package org.apache.atlas.authorize;
public enum AtlasActionTypes {
READ, CREATE, UPDATE, DELETE
import java.util.Set;
public class AtlasAdminAccessRequest extends AtlasAccessRequest {
public AtlasAdminAccessRequest(AtlasPrivilege action) {
super(action);
}
public AtlasAdminAccessRequest(AtlasPrivilege action, String userName, Set<String> usergroups) {
super(action, userName, usergroups);
}
@Override
public String toString() {
return "AtlasAdminAccessRequest[action=" + getAction() + ", accessTime=" + getAccessTime() + ", user=" + getUser() +
", userGroups=" + getUserGroups() + ", clientIPAddress=" + getClientIPAddress() + "]";
}
}
/**
/**
* 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.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
public class AtlasAuthorizationUtils {
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizationUtils.class);
public static void verifyAccess(AtlasAdminAccessRequest 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 verifyAccess(AtlasTypeAccessRequest 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 verifyAccess(AtlasEntityAccessRequest 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 boolean isAccessAllowed(AtlasAdminAccessRequest request) {
boolean ret = false;
String userName = getCurrentUserName();
if (StringUtils.isNotEmpty(userName)) {
try {
AtlasAuthorizer authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
request.setUser(userName, getCurrentUserGroups());
ret = authorizer.isAccessAllowed(request);
} catch (AtlasAuthorizationException e) {
LOG.error("Unable to obtain AtlasAuthorizer", e);
}
} else {
ret = true;
}
return ret;
}
public static boolean isAccessAllowed(AtlasEntityAccessRequest request) {
boolean ret = false;
String userName = getCurrentUserName();
if (StringUtils.isNotEmpty(userName)) {
try {
AtlasAuthorizer authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
request.setUser(getCurrentUserName(), getCurrentUserGroups());
ret = authorizer.isAccessAllowed(request);
} catch (AtlasAuthorizationException e) {
LOG.error("Unable to obtain AtlasAuthorizer", e);
}
} else {
ret = true;
}
return ret;
}
public static boolean isAccessAllowed(AtlasTypeAccessRequest request) {
boolean ret = false;
String userName = getCurrentUserName();
if (StringUtils.isNotEmpty(userName)) {
try {
AtlasAuthorizer authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
request.setUser(getCurrentUserName(), getCurrentUserGroups());
ret = authorizer.isAccessAllowed(request);
} catch (AtlasAuthorizationException e) {
LOG.error("Unable to obtain AtlasAuthorizer", e);
}
} else {
ret = true;
}
return ret;
}
public static String getRequestIpAddress(HttpServletRequest httpServletRequest) {
String ret = "";
try {
InetAddress inetAddr = InetAddress.getByName(httpServletRequest.getRemoteAddr());
ret = inetAddr.getHostAddress();
} catch (UnknownHostException ex) {
LOG.error("Failed to retrieve client IP address", ex);
}
return ret;
}
public static String getCurrentUserName() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return auth != null ? auth.getName() : "";
}
public static Set<String> getCurrentUserGroups() {
Set<String> ret = new HashSet<>();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
for (GrantedAuthority c : auth.getAuthorities()) {
ret.add(c.getAuthority());
}
}
return ret;
}
}
......@@ -20,23 +20,39 @@ package org.apache.atlas.authorize;
public interface AtlasAuthorizer {
/**
* initialization of authorizer implementation
*/
void init();
/**
* cleanup of authorizer implementation
*/
void cleanUp();
/**
* This method will load the policy file and would initialize the required data-structures.
* authorize admin operations
* @param request
* @return
* @throws AtlasAuthorizationException
*/
void init();
boolean isAccessAllowed(AtlasAdminAccessRequest request) throws AtlasAuthorizationException;
/**
* This method is responsible to perform the actual authorization for every REST API call. It will check if
* user can perform action on resource.
* authorize operations on an entity
* @param request
* @return
* @throws AtlasAuthorizationException
*/
boolean isAccessAllowed(AtlasAccessRequest request) throws AtlasAuthorizationException;
boolean isAccessAllowed(AtlasEntityAccessRequest request) throws AtlasAuthorizationException;
/**
* This method is responsible to perform the cleanup and release activities. It must be called when you are done
* with the Authorization activity and once it's called a restart would be required. Try to invoke this while
* destroying the context.
* authorize operations on a type
* @param request
* @return
* @throws AtlasAuthorizationException
*/
void cleanUp();
boolean isAccessAllowed(AtlasTypeAccessRequest request) throws AtlasAuthorizationException;
}
......@@ -20,65 +20,71 @@ package org.apache.atlas.authorize;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasException;
import org.apache.atlas.authorize.simple.AtlasSimpleAuthorizer;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AtlasAuthorizerFactory {
public class AtlasAuthorizerFactory {
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizerFactory.class);
private static final String SIMPLE_AUTHORIZER = "org.apache.atlas.authorize.simple.SimpleAtlasAuthorizer";
private static final String RANGER_AUTHORIZER =
"org.apache.ranger.authorization.atlas.authorizer.RangerAtlasAuthorizer";
private static final String NONE_AUTHORIZER = AtlasNoneAuthorizer.class.getName();
private static final String SIMPLE_AUTHORIZER = AtlasSimpleAuthorizer.class.getName();
private static final String RANGER_AUTHORIZER = "org.apache.ranger.authorization.atlas.authorizer.RangerAtlasAuthorizer";
private static volatile AtlasAuthorizer INSTANCE = null;
private static boolean isDebugEnabled = LOG.isDebugEnabled();
public static AtlasAuthorizer getAtlasAuthorizer() throws AtlasAuthorizationException {
Configuration configuration = null;
try {
configuration = ApplicationProperties.get();
} catch (AtlasException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Exception while fetching configuration. ", e);
}
}
AtlasAuthorizer ret = INSTANCE;
if (ret == null) {
synchronized (AtlasAuthorizerFactory.class) {
if (INSTANCE == null) {
String authorizerClass =
configuration != null ? configuration.getString("atlas.authorizer.impl") : "SIMPLE";
Configuration configuration = null;
try {
configuration = ApplicationProperties.get();
} catch (AtlasException e) {
LOG.error("Exception while fetching configuration", e);
}
String authorizerClass = configuration != null ? configuration.getString("atlas.authorizer.impl") : "SIMPLE";
if (StringUtils.isNotEmpty(authorizerClass)) {
if (StringUtils.equalsIgnoreCase(authorizerClass, "SIMPLE")) {
authorizerClass = SIMPLE_AUTHORIZER;
} else if (StringUtils.equalsIgnoreCase(authorizerClass, "RANGER")) {
authorizerClass = RANGER_AUTHORIZER;
} else if (StringUtils.equalsIgnoreCase(authorizerClass, "NONE")) {
authorizerClass = NONE_AUTHORIZER;
}
} else {
authorizerClass = SIMPLE_AUTHORIZER;
}
if (isDebugEnabled) {
LOG.debug("Initializing Authorizer :: {}", authorizerClass);
}
LOG.info("Initializing Authorizer {}", authorizerClass);
try {
Class authorizerMetaObject = Class.forName(authorizerClass);
if (authorizerMetaObject != null) {
INSTANCE = (AtlasAuthorizer) authorizerMetaObject.newInstance();
INSTANCE.init();
}
} catch (Exception e) {
LOG.error("Error while creating authorizer of type '{}", authorizerClass, e);
throw new AtlasAuthorizationException("Error while creating authorizer of type '"
+ authorizerClass + "'", e);
LOG.error("Error while creating authorizer of type {}", authorizerClass, e);
throw new AtlasAuthorizationException("Error while creating authorizer of type '" + authorizerClass + "'", e);
}
ret = INSTANCE;
}
ret = INSTANCE;
}
}
return ret;
}
}
/**
* 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.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.commons.lang.StringUtils;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class AtlasEntityAccessRequest extends AtlasAccessRequest {
private final AtlasEntityHeader entity;
private final String entityId;
private final AtlasClassification classification;
private final String attributeName;
private final AtlasTypeRegistry typeRegistry;
private final Set<String> entityClassifications;
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action) {
this(typeRegistry, action, null, null, null, null, null);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity) {
this(typeRegistry, action, entity, null, null, null, null);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification) {
this(typeRegistry, action, entity, classification, null, null, null);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String attributeName) {
this(typeRegistry, action, entity, null, attributeName, null, null);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String userName, Set<String> userGroups) {
this(typeRegistry, action, entity, null, null, userName, userGroups);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String userName, Set<String> userGroups) {
this(typeRegistry, action, entity, classification, null, userName, userGroups);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String attributeName, String userName, Set<String> userGroups) {
this(typeRegistry, action, entity, null, attributeName, userName, userGroups);
}
public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String attributeName, String userName, Set<String> userGroups) {
super(action, userName, userGroups);
this.entity = entity;
this.entityId = entity != null ? (String) entity.getAttribute("qualifiedName") : null;
this.classification = classification;
this.attributeName = attributeName;
this.typeRegistry = typeRegistry;
if (entity == null || entity.getClassifications() == null) {
this.entityClassifications = Collections.emptySet();
} else {
this.entityClassifications = new HashSet<>();
for (AtlasClassification classify : entity.getClassifications()) {
this.entityClassifications.add(classify.getTypeName());
}
}
}
public AtlasEntityHeader getEntity() {
return entity;
}
public String getEntityId() {
return entityId;
}
public AtlasClassification getClassification() {
return classification;
}
public String getAttributeName() {
return attributeName;
}
public String getEntityType() {
return entity == null ? StringUtils.EMPTY : entity.getTypeName();
}
public Set<String> getEntityClassifications() {
return entityClassifications;
}
public Set<String> getEntityTypeAndAllSuperTypes() {
final Set<String> ret;
if (entity == null) {
ret = Collections.emptySet();
} else if (typeRegistry == null) {
ret = Collections.singleton(entity.getTypeName());
} else {
AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entity.getTypeName());
ret = entityType != null ? entityType.getTypeAndAllSuperTypes() : Collections.singleton(entity.getTypeName());
}
return ret;
}
public Set<String> getClassificationTypeAndAllSuperTypes(String classificationName) {
if (typeRegistry != null && classificationName != null) {
AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classificationName);
return classificationType == null ? Collections.emptySet() : classificationType.getTypeAndAllSuperTypes();
}
return Collections.emptySet();
}
@Override
public String toString() {
return "AtlasEntityAccessRequest[entity=" + entity + ", classification=" + classification + ", attributeName" + attributeName +
", action=" + getAction() + ", accessTime=" + getAccessTime() + ", user=" + getUser() +
", userGroups=" + getUserGroups() + ", clientIPAddress=" + getClientIPAddress() + "]";
}
}
/**
/*
* 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
......@@ -16,30 +16,32 @@
* limitations under the License.
*/
package org.apache.atlas.exception;
package org.apache.atlas.authorize;
/**
* A simple wrapper for 404.
* Thrown when a requested trait can not be found.
*/
public class TraitNotFoundException extends NotFoundException {
public TraitNotFoundException() {
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AtlasNoneAuthorizer implements AtlasAuthorizer {
private static final Logger LOG = LoggerFactory.getLogger(AtlasNoneAuthorizer.class);
public void init() {
LOG.info("AtlasNoneAuthorizer.init()");
}
public TraitNotFoundException(String message) {
super(message);
public void cleanUp() {
LOG.info("AtlasNoneAuthorizer.cleanUp()");
}
public TraitNotFoundException(String message, Throwable cause) {
super(message, cause);
public boolean isAccessAllowed(AtlasAdminAccessRequest request) throws AtlasAuthorizationException {
return true;
}
public TraitNotFoundException(Throwable cause) {
super(cause);
public boolean isAccessAllowed(AtlasEntityAccessRequest request) throws AtlasAuthorizationException {
return true;
}
public TraitNotFoundException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
public boolean isAccessAllowed(AtlasTypeAccessRequest request) throws AtlasAuthorizationException {
return true;
}
}
......@@ -15,9 +15,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.atlas.authorize;
public enum AtlasResourceTypes {
UNKNOWN, ENTITY, TYPE, OPERATION, RELATIONSHIP
public enum AtlasPrivilege {
TYPE_CREATE("type-create"),
TYPE_UPDATE("type-update"),
TYPE_DELETE("type-delete"),
ENTITY_READ("entity-read"),
ENTITY_CREATE("entity-create"),
ENTITY_UPDATE("entity-update"),
ENTITY_DELETE("entity-delete"),
ENTITY_READ_CLASSIFICATION("entity-read-classification"),
ENTITY_ADD_CLASSIFICATION("entity-add-classification"),
ENTITY_UPDATE_CLASSIFICATION("entity-update-classification"),
ENTITY_REMOVE_CLASSIFICATION("entity-remove-classification"),
ADMIN_EXPORT("admin-export"),
ADMIN_IMPORT("admin-import");
private final String type;
AtlasPrivilege(String actionType){
this.type = actionType;
}
public String getType() {
return type;
}
}
......@@ -15,26 +15,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.atlas.exception;
package org.apache.atlas.authorize;
public class SchemaNotFoundException extends NotFoundException {
public SchemaNotFoundException() {
}
import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import java.util.Set;
public class AtlasTypeAccessRequest extends AtlasAccessRequest {
private final AtlasBaseTypeDef typeDef;
public SchemaNotFoundException(String message) {
super(message);
public AtlasTypeAccessRequest(AtlasPrivilege action, AtlasBaseTypeDef typeDef) {
super(action);
this.typeDef = typeDef;
}
public SchemaNotFoundException(String message, Throwable cause) {
super(message, cause);
public AtlasTypeAccessRequest(AtlasPrivilege action, AtlasBaseTypeDef typeDef, String userName, Set<String> usergroups) {
super(action, userName, usergroups);
this.typeDef = typeDef;
}
public SchemaNotFoundException(Throwable cause) {
super(cause);
public AtlasBaseTypeDef getTypeDef() {
return typeDef;
}
public SchemaNotFoundException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
@Override
public String toString() {
return "AtlasEntityAccessRequest[typeDef=" + typeDef + ", action=" + getAction() + ", accessTime=" + getAccessTime() +
", user=" + getUser() + ", userGroups=" + getUserGroups() + ", clientIPAddress=" + getClientIPAddress() + "]";
}
}
/**
/**
* 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.simple;
import org.apache.atlas.authorize.AtlasAccessRequest;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasAuthorizationException;
import org.apache.atlas.authorize.AtlasAuthorizer;
import org.apache.atlas.authorize.AtlasAuthorizerFactory;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
public class AtlasAuthorizationUtils {
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizationUtils.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
private static final String BASE_URL = "/api/atlas/";
public static String getApi(String contextPath) {
if (isDebugEnabled) {
LOG.debug("==> getApi({})", contextPath);
}
if(contextPath == null){
contextPath = "";
}
if (contextPath.startsWith(BASE_URL)) {
contextPath = contextPath.substring(BASE_URL.length());
} else {
// strip of leading '/'
if (contextPath.startsWith("/")) {
contextPath = contextPath.substring(1);
}
}
String[] split = contextPath.split("/", 3);
String api = split[0];
if (Pattern.matches("v\\d", api)) {
api = split[1];
}
if (isDebugEnabled) {
LOG.debug("<== getApi({}): {}", contextPath, api);
}
return api;
}
public static AtlasActionTypes getAtlasAction(String method, String contextPath) {
AtlasActionTypes action = null;
switch (method.toUpperCase()) {
case "POST":
String api = getApi(contextPath);
if (api != null && api.startsWith("search")) { // exceptional case for basic search api with POST method
action = AtlasActionTypes.READ;
} else {
action = AtlasActionTypes.CREATE;
}
break;
case "GET":
action = AtlasActionTypes.READ;
break;
case "PUT":
action = AtlasActionTypes.UPDATE;
break;
case "DELETE":
action = AtlasActionTypes.DELETE;
break;
default:
if (isDebugEnabled) {
LOG.debug("getAtlasAction(): Invalid HTTP method '{}", method);
}
break;
}
if (isDebugEnabled) {
LOG.debug("<== AtlasAuthorizationFilter getAtlasAction HTTP Method {} mapped to AtlasAction : {}",
method, action);
}
return action;
}
/**
* @param contextPath
* @return set of AtlasResourceTypes types api mapped with AtlasResourceTypes.TYPE eg :- /api/atlas/types/*
*
* gremlin discovery,admin,graph apis are mapped with AtlasResourceTypes.OPERATION eg :-/api/atlas/admin/*
* /api/atlas/discovery/search/gremlin /api/atlas/graph/*
*
* entities,lineage and discovery apis are mapped with AtlasResourceTypes.ENTITY eg :- /api/atlas/lineage/hive/table/*
* /api/atlas/entities/{guid}* /api/atlas/discovery/*
*
* unprotected types are mapped with AtlasResourceTypes.UNKNOWN, access to these are allowed.
*/
public static Set<AtlasResourceTypes> getAtlasResourceType(String contextPath) {
Set<AtlasResourceTypes> resourceTypes = new HashSet<>();
if (isDebugEnabled) {
LOG.debug("==> getAtlasResourceType for {}", contextPath);
}
String api = getApi(contextPath);
if (api.startsWith("types")) {
resourceTypes.add(AtlasResourceTypes.TYPE);
} else if (api.startsWith("admin") && (contextPath.contains("/session") || contextPath.contains("/version"))) {
resourceTypes.add(AtlasResourceTypes.UNKNOWN);
} else if ((api.startsWith("discovery") && contextPath.contains("/gremlin")) || api.startsWith("admin")
|| api.startsWith("graph")) {
resourceTypes.add(AtlasResourceTypes.OPERATION);
} else if (api.startsWith("entities") || api.startsWith("lineage") ||
api.startsWith("discovery") || api.startsWith("entity") || api.startsWith("search")) {
resourceTypes.add(AtlasResourceTypes.ENTITY);
} else if (api.startsWith("relationship")) {
resourceTypes.add(AtlasResourceTypes.RELATIONSHIP);
} else {
LOG.error("Unable to find Atlas Resource corresponding to : {}\nSetting {}"
, api, AtlasResourceTypes.UNKNOWN.name());
resourceTypes.add(AtlasResourceTypes.UNKNOWN);
}
if (isDebugEnabled) {
LOG.debug("<== Returning AtlasResources {} for api {}", resourceTypes, api);
}
return resourceTypes;
}
public static boolean isAccessAllowed(AtlasResourceTypes resourcetype, AtlasActionTypes actionType, String userName, Set<String> groups, HttpServletRequest request) {
AtlasAuthorizer authorizer = null;
boolean isaccessAllowed = false;
Set<AtlasResourceTypes> resourceTypes = new HashSet<>();
resourceTypes.add(resourcetype);
AtlasAccessRequest atlasRequest = new AtlasAccessRequest(resourceTypes, "*", actionType, userName, groups, AtlasAuthorizationUtils.getRequestIpAddress(request));
try {
authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
if (authorizer != null) {
isaccessAllowed = authorizer.isAccessAllowed(atlasRequest);
}
} catch (AtlasAuthorizationException e) {
LOG.error("Unable to obtain AtlasAuthorizer. ", e);
}
return isaccessAllowed;
}
public static String getRequestIpAddress(HttpServletRequest httpServletRequest) {
try {
InetAddress inetAddr = InetAddress.getByName(httpServletRequest.getRemoteAddr());
String ip = inetAddr.getHostAddress();
return ip;
} catch (UnknownHostException ex) {
LOG.error("Error occured when retrieving IP address", ex);
return "";
}
}
}
/** 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.simple;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class AtlasSimpleAuthzPolicy implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, AtlasAuthzRole> roles;
private Map<String, List<String>> userRoles;
private Map<String, List<String>> groupRoles;
public Map<String, AtlasAuthzRole> getRoles() {
return roles;
}
public void setRoles(Map<String, AtlasAuthzRole> roles) {
this.roles = roles;
}
public Map<String, List<String>> getUserRoles() {
return userRoles;
}
public void setUserRoles(Map<String, List<String>> userRoles) {
this.userRoles = userRoles;
}
public Map<String, List<String>> getGroupRoles() {
return groupRoles;
}
public void setGroupRoles(Map<String, List<String>> groupRoles) {
this.groupRoles = groupRoles;
}
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class AtlasAuthzRole implements Serializable {
private static final long serialVersionUID = 1L;
private List<AtlasAdminPermission> adminPermissions;
private List<AtlasEntityPermission> entityPermissions;
private List<AtlasTypePermission> typePermissions;
public AtlasAuthzRole() {
}
public AtlasAuthzRole(List<AtlasAdminPermission> adminPermissions, List<AtlasEntityPermission> entityPermissions, List<AtlasTypePermission> typePermissions) {
this.adminPermissions = adminPermissions;
this.entityPermissions = entityPermissions;
this.typePermissions = typePermissions;
}
public List<AtlasAdminPermission> getAdminPermissions() {
return adminPermissions;
}
public void setAdminPermissions(List<AtlasAdminPermission> adminPermissions) {
this.adminPermissions = adminPermissions;
}
public List<AtlasEntityPermission> getEntityPermissions() {
return entityPermissions;
}
public void setEntityPermissions(List<AtlasEntityPermission> entityPermissions) {
this.entityPermissions = entityPermissions;
}
public List<AtlasTypePermission> getTypePermissions() {
return typePermissions;
}
public void setTypePermissions(List<AtlasTypePermission> typePermissions) {
this.typePermissions = typePermissions;
}
}
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class AtlasAdminPermission implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> privileges; // name of AtlasPrivilege enum, wildcards supported
public AtlasAdminPermission() {
}
public AtlasAdminPermission(List<String> privileges) {
this.privileges = privileges;
}
public List<String> getPrivileges() {
return privileges;
}
public void setPrivileges(List<String> privileges) {
this.privileges = privileges;
}
}
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class AtlasTypePermission implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> privileges; // name of AtlasPrivilege enum, wildcards supported
private List<String> typeCategories; // category of the type (entity, classification, struct, enum, relationship), wildcards supported
private List<String> typeNames; // name of type, wildcards supported
public AtlasTypePermission() {
}
public AtlasTypePermission(List<String> privileges, List<String> typeCategories, List<String> typeNames) {
this.privileges = privileges;
this.typeCategories = typeCategories;
this.typeNames = typeNames;
}
public List<String> getPrivileges() {
return privileges;
}
public void setPrivileges(List<String> privileges) {
this.privileges = privileges;
}
public List<String> getTypeCategories() {
return typeCategories;
}
public void setTypeCategories(List<String> typeCategories) {
this.typeCategories = typeCategories;
}
public List<String> getTypeNames() {
return typeNames;
}
public void setTypeNames(List<String> typeNames) {
this.typeNames = typeNames;
}
}
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
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> attributes; // name of entity-attribute, wildcards supported
public AtlasEntityPermission() {
}
public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> attributes) {
this.privileges = privileges;
this.entityTypes = entityTypes;
this.entityIds = entityIds;
this.classifications = classifications;
this.attributes = attributes;
}
public List<String> getPrivileges() {
return privileges;
}
public void setPrivileges(List<String> privileges) {
this.privileges = privileges;
}
public List<String> getEntityTypes() {
return entityTypes;
}
public void setEntityTypes(List<String> entityTypes) {
this.entityTypes = entityTypes;
}
public List<String> getEntityIds() {
return entityIds;
}
public void setEntityIds(List<String> entityIds) {
this.entityIds = entityIds;
}
public List<String> getClassifications() {
return classifications;
}
public void setClassifications(List<String> classifications) {
this.classifications = classifications;
}
public List<String> getAttributes() {
return attributes;
}
public void setAttributes(List<String> attributes) {
this.attributes = attributes;
}
}
}
/**
* 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.simple;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileReaderUtil {
private static Logger LOG = LoggerFactory.getLogger(FileReaderUtil.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
public static List<String> readFile(InputStream policyStoreStream) throws IOException {
if (isDebugEnabled) {
LOG.debug("==> FileReaderUtil readFile()");
}
List<String> list = new ArrayList<>();
List<String> fileLines = IOUtils.readLines(policyStoreStream, StandardCharsets.UTF_8);
if (fileLines != null) {
for (String line : fileLines) {
if ((!line.startsWith("#")) && Pattern.matches(".+;;.*;;.*;;.+", line))
list.add(line);
}
}
if (isDebugEnabled) {
LOG.debug("<== FileReaderUtil readFile()");
LOG.debug("Policies read :: " + list);
}
return list;
}
}
\ No newline at end of file
/** 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.simple;
import java.util.List;
import java.util.Map;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
public class PolicyDef {
private String policyName;
private Map<String, List<AtlasActionTypes>> users;
private Map<String, List<AtlasActionTypes>> groups;
private Map<AtlasResourceTypes, List<String>> resources;
public String getPolicyName() {
return policyName;
}
public void setPolicyName(String policyName) {
this.policyName = policyName;
}
public Map<String, List<AtlasActionTypes>> getUsers() {
return users;
}
public void setUsers(Map<String, List<AtlasActionTypes>> users) {
this.users = users;
}
public Map<String, List<AtlasActionTypes>> getGroups() {
return groups;
}
public void setGroups(Map<String, List<AtlasActionTypes>> groups) {
this.groups = groups;
}
public Map<AtlasResourceTypes, List<String>> getResources() {
return resources;
}
public void setResources(Map<AtlasResourceTypes, List<String>> resources) {
this.resources = resources;
}
@Override
public String toString() {
return "PolicyDef [policyName=" + policyName + ", users=" + users + ", groups=" + groups + ", resources="
+ resources + "]";
}
}
/**
* 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.simple;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class PolicyParser {
private static Logger LOG = LoggerFactory.getLogger(PolicyParser.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
public static final int POLICYNAME = 0;
public static final int USER_INDEX = 1;
public static final int USERNAME = 0;
public static final int USER_AUTHORITIES = 1;
public static final int GROUP_INDEX = 2;
public static final int GROUPNAME = 0;
public static final int GROUP_AUTHORITIES = 1;
public static final int RESOURCE_INDEX = 3;
public static final int RESOURCE_TYPE = 0;
public static final int RESOURCE_NAME = 1;
private List<AtlasActionTypes> getListOfAutorities(String auth) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser getListOfAutorities");
}
List<AtlasActionTypes> authorities = new ArrayList<>();
for (int i = 0; i < auth.length(); i++) {
char access = auth.toLowerCase().charAt(i);
switch (access) {
case 'r':
authorities.add(AtlasActionTypes.READ);
break;
case 'w':
authorities.add(AtlasActionTypes.CREATE);
break;
case 'u':
authorities.add(AtlasActionTypes.UPDATE);
break;
case 'd':
authorities.add(AtlasActionTypes.DELETE);
break;
default:
if (LOG.isErrorEnabled()) {
LOG.error("Invalid action: '{}'", access);
}
break;
}
}
if (isDebugEnabled) {
LOG.debug("<== PolicyParser getListOfAutorities");
}
return authorities;
}
public List<PolicyDef> parsePolicies(List<String> policies) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser parsePolicies");
}
List<PolicyDef> policyDefs = new ArrayList<>();
for (String policy : policies) {
PolicyDef policyDef = parsePolicy(policy);
if (policyDef != null) {
policyDefs.add(policyDef);
}
}
if (isDebugEnabled) {
LOG.debug("<== PolicyParser parsePolicies");
LOG.debug(policyDefs.toString());
}
return policyDefs;
}
private PolicyDef parsePolicy(String data) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser parsePolicy");
}
PolicyDef def = null;
String[] props = data.split(";;");
if (props.length < RESOURCE_INDEX) {
LOG.warn("skipping invalid policy line: {}", data);
} else {
def = new PolicyDef();
def.setPolicyName(props[POLICYNAME]);
parseUsers(props[USER_INDEX], def);
parseGroups(props[GROUP_INDEX], def);
parseResources(props[RESOURCE_INDEX], def);
if (isDebugEnabled) {
LOG.debug("policy successfully parsed!!!");
LOG.debug("<== PolicyParser parsePolicy");
}
}
return def;
}
private boolean validateEntity(String entity) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser validateEntity");
}
boolean isValidEntity = Pattern.matches("(.+:.+)+", entity);
boolean isEmpty = entity.isEmpty();
if (!isValidEntity || isEmpty) {
if (isDebugEnabled) {
LOG.debug("group/user/resource not properly define in Policy");
LOG.debug("<== PolicyParser validateEntity");
}
return false;
} else {
if (isDebugEnabled) {
LOG.debug("<== PolicyParser validateEntity");
}
return true;
}
}
private void parseUsers(String usersDef, PolicyDef def) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser parseUsers");
}
String[] users = usersDef.split(",");
String[] userAndRole = null;
Map<String, List<AtlasActionTypes>> usersMap = new HashMap<>();
if (validateEntity(usersDef)) {
for (String user : users) {
if (!Pattern.matches("(.+:.+)+", user)) {
continue;
}
userAndRole = user.split(":");
if (def.getUsers() != null) {
usersMap = def.getUsers();
}
List<AtlasActionTypes> userAutorities = getListOfAutorities(userAndRole[USER_AUTHORITIES]);
usersMap.put(userAndRole[USERNAME], userAutorities);
def.setUsers(usersMap);
}
} else {
def.setUsers(usersMap);
}
if (isDebugEnabled) {
LOG.debug("<== PolicyParser parseUsers");
}
}
private void parseGroups(String groupsDef, PolicyDef def) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser parseGroups");
}
String[] groups = groupsDef.split("\\,");
String[] groupAndRole = null;
Map<String, List<AtlasActionTypes>> groupsMap = new HashMap<>();
if (validateEntity(groupsDef.trim())) {
for (String group : groups) {
if (!Pattern.matches("(.+:.+)+", group)) {
continue;
}
groupAndRole = group.split("[:]");
if (def.getGroups() != null) {
groupsMap = def.getGroups();
}
List<AtlasActionTypes> groupAutorities = getListOfAutorities(groupAndRole[GROUP_AUTHORITIES]);
groupsMap.put(groupAndRole[GROUPNAME], groupAutorities);
def.setGroups(groupsMap);
}
} else {
def.setGroups(groupsMap);
}
if (isDebugEnabled) {
LOG.debug("<== PolicyParser parseGroups");
}
}
private void parseResources(String resourceDef, PolicyDef def) {
if (isDebugEnabled) {
LOG.debug("==> PolicyParser parseResources");
}
String[] resources = resourceDef.split(",");
String[] resourceTypeAndName = null;
Map<AtlasResourceTypes, List<String>> resourcesMap = new HashMap<>();
if (validateEntity(resourceDef)) {
for (String resource : resources) {
if (!Pattern.matches("(.+:.+)+", resource)) {
continue;
}
resourceTypeAndName = resource.split("[:]");
if (def.getResources() != null) {
resourcesMap = def.getResources();
}
AtlasResourceTypes resourceType = null;
String type = resourceTypeAndName[RESOURCE_TYPE].toUpperCase();
if (type.equalsIgnoreCase("ENTITY")) {
resourceType = AtlasResourceTypes.ENTITY;
} else if (type.equalsIgnoreCase("OPERATION")) {
resourceType = AtlasResourceTypes.OPERATION;
} else if (type.equalsIgnoreCase("TYPE")) {
resourceType = AtlasResourceTypes.TYPE;
} else if (type.equalsIgnoreCase("RELATIONSHIP")) {
resourceType = AtlasResourceTypes.RELATIONSHIP;
} else {
LOG.warn(type + " is invalid resource please check PolicyStore file");
continue;
}
List<String> resourceList = resourcesMap.get(resourceType);
if (resourceList == null) {
resourceList = new ArrayList<>();
}
resourceList.add(resourceTypeAndName[RESOURCE_NAME]);
resourcesMap.put(resourceType, resourceList);
def.setResources(resourcesMap);
}
} else {
def.setResources(resourcesMap);
}
if (isDebugEnabled) {
LOG.debug("<== PolicyParser parseResources");
}
}
}
/** 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.simple;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PolicyUtil {
private static Logger LOG = LoggerFactory.getLogger(PolicyUtil.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
public static Map<String, Map<AtlasResourceTypes, List<String>>> createPermissionMap(List<PolicyDef> policyDefList,
AtlasActionTypes permissionType, SimpleAtlasAuthorizer.AtlasAccessorTypes principalType) {
if (isDebugEnabled) {
LOG.debug("==> PolicyUtil createPermissionMap\nCreating Permission Map for :: {} & {}", permissionType, principalType);
}
Map<String, Map<AtlasResourceTypes, List<String>>> userReadMap =
new HashMap<>();
// Iterate over the list of policies to create map
for (PolicyDef policyDef : policyDefList) {
if (LOG.isDebugEnabled()) {
LOG.debug("Processing policy def : {}", policyDef);
}
Map<String, List<AtlasActionTypes>> principalMap =
principalType.equals(SimpleAtlasAuthorizer.AtlasAccessorTypes.USER) ? policyDef.getUsers() : policyDef
.getGroups();
// For every policy extract the resource list and populate the user map
for (Entry<String, List<AtlasActionTypes>> e : principalMap.entrySet()) {
// Check if the user has passed permission type like READ
if (!e.getValue().contains(permissionType)) {
continue;
}
// See if the current user is already added to map
String username = e.getKey();
Map<AtlasResourceTypes, List<String>> userResourceList = userReadMap.get(username);
// If its not added then create a new resource list
if (userResourceList == null) {
if (isDebugEnabled) {
LOG.debug("Resource list not found for {}, creating it", username);
}
userResourceList = new HashMap<>();
}
/*
* Iterate over resources from the current policy def and update the resource list for the current user
*/
for (Entry<AtlasResourceTypes, List<String>> resourceTypeMap : policyDef.getResources().entrySet()) {
// For the current resourceType in the policyDef, get the
// current list of resources already added
AtlasResourceTypes type = resourceTypeMap.getKey();
List<String> resourceList = userResourceList.get(type);
if (resourceList == null) {
// if the resource list was not added for this type then
// create and add all the resources in this policy
resourceList = new ArrayList<>();
resourceList.addAll(resourceTypeMap.getValue());
} else {
// if the resource list is present then merge both the
// list
resourceList.removeAll(resourceTypeMap.getValue());
resourceList.addAll(resourceTypeMap.getValue());
}
userResourceList.put(type, resourceList);
}
userReadMap.put(username, userResourceList);
if (LOG.isDebugEnabled()) {
LOG.debug("userReadMap {}", userReadMap);
}
}
}
if (isDebugEnabled) {
LOG.debug("Returning Map for {} :: {}", principalType, userReadMap);
LOG.debug("<== PolicyUtil createPermissionMap");
}
return userReadMap;
}
}
{
"roles": {
"ROLE_ADMIN": {
"adminPermissions": [
{
"privileges": [ ".*" ]
}
],
"entityPermissions": [
{
"privileges": [ ".*" ],
"entityTypes": [ ".*" ],
"entityIds": [ ".*" ],
"classifications": [ ".*" ]
}
],
"typePermissions": [
{
"privileges": [ ".*" ],
"typeCategories": [ ".*" ],
"typeNames": [ ".*" ]
}
]
},
"DATA_SCIENTIST": {
"entityPermissions": [
{
"privileges": [ "entity-read", "entity-read-classification" ],
"entityTypes": [ ".*" ],
"entityIds": [ ".*" ],
"classifications": [ ".*" ]
}
]
},
"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": [ ".*" ]
}
]
}
},
"userRoles": {
"admin": [ "ROLE_ADMIN" ]
},
"groupRoles": {
"ROLE_ADMIN": [ "ROLE_ADMIN" ],
"hadoop": [ "DATA_STEWARD" ],
"DATA_STEWARD": [ "DATA_STEWARD" ],
"RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ]
}
}
/**
* 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.simple;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.testng.annotations.Test;
import java.util.Set;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/**
* Unit tests for AtlasAuthorizationUtils.
*/
public class AtlasAuthorizationUtilsTest {
@Test
public void testGetApi() {
String contextPath = "/api/atlas/entities";
assertEquals(AtlasAuthorizationUtils.getApi(contextPath), "entities");
contextPath = "/api/atlas/entities/111/traits";
assertEquals(AtlasAuthorizationUtils.getApi(contextPath), "entities");
contextPath = "/api/atlas/v1/entities";
assertEquals(AtlasAuthorizationUtils.getApi(contextPath), "entities");
contextPath = "/api/atlas/v1/entities/111/tags";
assertEquals(AtlasAuthorizationUtils.getApi(contextPath), "entities");
// not sure of this use case but the code appears to support url's that don't
// begin with base url.
contextPath = "/foo/bar";
assertEquals(AtlasAuthorizationUtils.getApi(contextPath), "foo");
}
@Test
public void testGetAtlasResourceType() throws Exception {
String contextPath = "/api/atlas/types";
Set<AtlasResourceTypes> resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.TYPE));
contextPath = "/api/atlas/admin/foo";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.OPERATION));
contextPath = "/api/atlas/graph/foo";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.OPERATION));
contextPath = "/api/atlas/discovery/search/gremlin";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.OPERATION));
contextPath = "/api/atlas/entities/111/traits";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
contextPath = "/api/atlas/discovery/search";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
contextPath = "/api/atlas/entities?type=Column";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
contextPath = "/api/atlas/lineage";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
contextPath = "/api/atlas/v1/entities/111";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
contextPath = "/api/atlas/v1/entities/111/tags/foo";
resourceTypes = AtlasAuthorizationUtils.getAtlasResourceType(contextPath);
assertEquals(resourceTypes.size(), 1);
assertTrue(resourceTypes.contains(AtlasResourceTypes.ENTITY));
}
}
/*
* 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.simple;
import org.apache.atlas.authorize.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.testng.AssertJUnit;
import java.util.Collections;
public class AtlasSimpleAuthorizerTest {
private static Logger LOG = LoggerFactory.getLogger(AtlasSimpleAuthorizerTest.class);
private String originalConf;
private AtlasAuthorizer authorizer;
@BeforeMethod
public void setup1() {
originalConf = System.getProperty("atlas.conf");
System.setProperty("atlas.conf", "src/test/resources");
try {
authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
} catch (Exception e) {
LOG.error("Exception in AtlasSimpleAuthorizerTest setup failed", e);
}
}
@AfterClass
public void tearDown() throws Exception {
if (originalConf != null) {
System.setProperty("atlas.conf", originalConf);
}
authorizer = null;
}
@Test(enabled = true)
public void testAccessAllowedForUserAndGroup() {
try {
AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
request.setUser("admin", Collections.singleton("ROLE_ADMIN"));
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(true, isAccessAllowed);
} catch (Exception e) {
LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
AssertJUnit.fail();
}
}
@Test(enabled = true)
public void testAccessAllowedForGroup() {
try {
AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
request.setUser("nonmappeduser", Collections.singleton("ROLE_ADMIN"));
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(true, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
AssertJUnit.fail();
}
}
@Test(enabled = true)
public void testAccessNotAllowedForUserAndGroup() {
try {
AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE);
request.setUser("nonmappeduser", Collections.singleton("GROUP-NOT-IN-POLICYFILE"));
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(false, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
AssertJUnit.fail();
}
}
}
/*
* 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.simple;
import static org.testng.AssertJUnit.assertEquals;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.apache.atlas.authorize.simple.PolicyDef;
import org.apache.atlas.authorize.simple.PolicyParser;
import org.testng.annotations.Test;
public class PolicyParserTest {
@Test
public void testParsePoliciesWithAllProperties() {
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;entity:*abc,operation:*xyz,type:PII");
/* Creating group data */
Map<String, List<AtlasActionTypes>> groupMap = new HashMap<>();
List<AtlasActionTypes> accessList1 = new ArrayList<>();
accessList1.add(AtlasActionTypes.READ);
accessList1.add(AtlasActionTypes.CREATE);
accessList1.add(AtlasActionTypes.UPDATE);
groupMap.put("grp1", accessList1);
List<AtlasActionTypes> accessList2 = new ArrayList<>();
accessList2.add(AtlasActionTypes.UPDATE);
groupMap.put("grp2", accessList2);
/* Creating user data */
Map<String, List<AtlasActionTypes>> usersMap = new HashMap<>();
List<AtlasActionTypes> usr1AccessList = new ArrayList<>();
usr1AccessList.add(AtlasActionTypes.READ);
usersMap.put("usr1", usr1AccessList);
List<AtlasActionTypes> usr2AccessList = new ArrayList<>();
usr2AccessList.add(AtlasActionTypes.READ);
usr2AccessList.add(AtlasActionTypes.CREATE);
usersMap.put("usr2", usr2AccessList);
/* Creating resources data */
Map<AtlasResourceTypes, List<String>> resourceMap = new HashMap<>();
List<String> resource1List = new ArrayList<>();
resource1List.add("*abc");
resourceMap.put(AtlasResourceTypes.ENTITY, resource1List);
List<String> resource2List = new ArrayList<>();
resource2List.add("*xyz");
resourceMap.put(AtlasResourceTypes.OPERATION, resource2List);
List<String> resource3List = new ArrayList<>();
resource3List.add("PII");
resourceMap.put(AtlasResourceTypes.TYPE, resource3List);
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
for (PolicyDef def : policyDefs) {
assertEquals(def.getPolicyName(), "hivePolicy");
assertEquals(def.getGroups(), groupMap);
assertEquals(def.getUsers(), usersMap);
assertEquals(def.getResources(), resourceMap);
}
}
@Test
public void testParsePoliciesWithOutUserProperties() {
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;;;grp1:rwu,grp2:u;;entity:*abc,operation:*xyz,type:PII");
// Creating group data
Map<String, List<AtlasActionTypes>> groupMap = new HashMap<>();
List<AtlasActionTypes> accessList1 = new ArrayList<>();
accessList1.add(AtlasActionTypes.READ);
accessList1.add(AtlasActionTypes.CREATE);
accessList1.add(AtlasActionTypes.UPDATE);
groupMap.put("grp1", accessList1);
List<AtlasActionTypes> accessList2 = new ArrayList<>();
accessList2.add(AtlasActionTypes.UPDATE);
groupMap.put("grp2", accessList2);
// Creating user data
Map<String, List<AtlasActionTypes>> usersMap = new HashMap<>();
// Creating resources data
Map<AtlasResourceTypes, List<String>> resourceMap = new HashMap<>();
List<String> resource1List = new ArrayList<>();
resource1List.add("*abc");
resourceMap.put(AtlasResourceTypes.ENTITY, resource1List);
List<String> resource2List = new ArrayList<>();
resource2List.add("*xyz");
resourceMap.put(AtlasResourceTypes.OPERATION, resource2List);
List<String> resource3List = new ArrayList<>();
resource3List.add("PII");
resourceMap.put(AtlasResourceTypes.TYPE, resource3List);
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
for (PolicyDef def : policyDefs) {
assertEquals(def.getPolicyName(), "hivePolicy");
assertEquals(def.getGroups(), groupMap);
assertEquals(def.getUsers(), usersMap);
assertEquals(def.getResources(), resourceMap);
}
}
@Test
public void testParsePoliciesWithOutGroupProperties() {
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;;;entity:*abc,operation:*xyz,type:PII");
// Creating group data
Map<String, List<AtlasActionTypes>> groupMap = new HashMap<>();
// Creating user data
Map<String, List<AtlasActionTypes>> usersMap = new HashMap<>();
List<AtlasActionTypes> usr1AccessList = new ArrayList<>();
usr1AccessList.add(AtlasActionTypes.READ);
usersMap.put("usr1", usr1AccessList);
List<AtlasActionTypes> usr2AccessList = new ArrayList<>();
usr2AccessList.add(AtlasActionTypes.READ);
usr2AccessList.add(AtlasActionTypes.CREATE);
usersMap.put("usr2", usr2AccessList);
// Creating resources data
Map<AtlasResourceTypes, List<String>> resourceMap = new HashMap<>();
List<String> resource1List = new ArrayList<>();
resource1List.add("*abc");
resourceMap.put(AtlasResourceTypes.ENTITY, resource1List);
List<String> resource2List = new ArrayList<>();
resource2List.add("*xyz");
resourceMap.put(AtlasResourceTypes.OPERATION, resource2List);
List<String> resource3List = new ArrayList<>();
resource3List.add("PII");
resourceMap.put(AtlasResourceTypes.TYPE, resource3List);
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
for (PolicyDef def : policyDefs) {
assertEquals(def.getPolicyName(), "hivePolicy");
assertEquals(def.getGroups(), groupMap);
assertEquals(def.getUsers(), usersMap);
assertEquals(def.getResources(), resourceMap);
}
}
}
\ No newline at end of file
/*
* 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.simple;
import static org.testng.AssertJUnit.assertEquals;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.atlas.authorize.simple.SimpleAtlasAuthorizer;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.apache.atlas.authorize.simple.PolicyDef;
import org.apache.atlas.authorize.simple.PolicyParser;
import org.apache.atlas.authorize.simple.PolicyUtil;
import org.testng.annotations.Test;
public class PolicyUtilTest {
@Test
public void testCreatePermissionMap() {
HashMap<AtlasResourceTypes, List<String>> resourceMap = new HashMap<>();
List<String> resource1List = new ArrayList<>();
resource1List.add("*abc");
resourceMap.put(AtlasResourceTypes.ENTITY, resource1List);
List<String> resource2List = new ArrayList<>();
resource2List.add("*xyz");
resourceMap.put(AtlasResourceTypes.OPERATION, resource2List);
List<String> resource3List = new ArrayList<>();
resource3List.add("PII");
resourceMap.put(AtlasResourceTypes.TYPE, resource3List);
Map<String, HashMap<AtlasResourceTypes, List<String>>> permissionMap =
new HashMap<>();
permissionMap.put("grp1", resourceMap);
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;entity:*abc,operation:*xyz,type:PII");
List<PolicyDef> policyDefList = new PolicyParser().parsePolicies(policies);
Map<String, Map<AtlasResourceTypes, List<String>>> createdPermissionMap =
new PolicyUtil().createPermissionMap(policyDefList, AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
assertEquals(permissionMap, createdPermissionMap);
}
@Test
public void testMergeCreatePermissionMap() {
HashMap<AtlasResourceTypes, List<String>> resourceMap = new HashMap<>();
List<String> resource1List = new ArrayList<>();
resource1List.add("*abc");
resourceMap.put(AtlasResourceTypes.ENTITY, resource1List);
List<String> resource2List = new ArrayList<>();
resource2List.add("*x");
resource2List.add("*xyz");
resourceMap.put(AtlasResourceTypes.OPERATION, resource2List);
List<String> resource3List = new ArrayList<>();
resource3List.add("PII");
resourceMap.put(AtlasResourceTypes.TYPE, resource3List);
Map<String, HashMap<AtlasResourceTypes, List<String>>> permissionMap =
new HashMap<>();
permissionMap.put("grp1", resourceMap);
List<String> policies = new ArrayList<>();
policies.add("hivePolicys;;;;grp1:rwu;;entity:*abc,operation:*xyz,operation:*x");
policies.add("hivePolicy;;;;grp1:rwu;;entity:*abc,operation:*xyz");
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu;;entity:*abc,operation:*xyz");
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;entity:*abc,operation:*xyz,type:PII");
List<PolicyDef> policyDefList = new PolicyParser().parsePolicies(policies);
Map<String, Map<AtlasResourceTypes, List<String>>> createdPermissionMap =
new PolicyUtil().createPermissionMap(policyDefList, AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
assertEquals(permissionMap, createdPermissionMap);
}
}
/*
* 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.simple;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import org.apache.atlas.authorize.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;
public class SimpleAtlasAuthorizerTest {
private static Logger LOG = LoggerFactory
.getLogger(SimpleAtlasAuthorizerTest.class);
@Test
public void testAccessAllowedForUserAndGroup() {
Map<String, Map<AtlasResourceTypes, List<String>>> userReadMap = null;
Map<String, Map<AtlasResourceTypes, List<String>>> groupReadMap = null;
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;type:*abc,type:PII");
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
PolicyUtil policyUtil = new PolicyUtil();
// group read map
groupReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
// creating user readMap
userReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.USER);
Set<AtlasResourceTypes> resourceType = new HashSet<>();
resourceType.add(AtlasResourceTypes.TYPE);
String resource = "xsdfhjabc";
AtlasActionTypes action = AtlasActionTypes.READ;
String user = "usr1";
Set<String> userGroups = new HashSet<>();
userGroups.add("grp3");
try {
AtlasAccessRequest request = new AtlasAccessRequest(resourceType,
resource, action, user, userGroups,"127.0.0.1");
SimpleAtlasAuthorizer authorizer = (SimpleAtlasAuthorizer) AtlasAuthorizerFactory
.getAtlasAuthorizer();
authorizer
.setResourcesForTesting(userReadMap, groupReadMap, action);
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
// getUserReadMap
AssertJUnit.assertEquals(true, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("AtlasAuthorizationException in Unit Test", e);
}
}
}
@Test
public void testAccessAllowedForGroup() {
Map<String, Map<AtlasResourceTypes, List<String>>> userReadMap = null;
Map<String, Map<AtlasResourceTypes, List<String>>> groupReadMap = null;
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;type:PII");
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
PolicyUtil policyUtil = new PolicyUtil();
// creating group read map
groupReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
// creating user readMap
userReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.USER);
Set<AtlasResourceTypes> resourceType = new HashSet<>();
resourceType.add(AtlasResourceTypes.TYPE);
String resource = "PII";
AtlasActionTypes action = AtlasActionTypes.READ;
String user = "usr3";
Set<String> userGroups = new HashSet<>();
userGroups.add("grp1");
AtlasAccessRequest request = new AtlasAccessRequest(resourceType,
resource, action, user, userGroups,"127.0.0.1");
try {
SimpleAtlasAuthorizer authorizer = (SimpleAtlasAuthorizer) AtlasAuthorizerFactory
.getAtlasAuthorizer();
authorizer
.setResourcesForTesting(userReadMap, groupReadMap, action);
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(true, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("AtlasAuthorizationException in Unit Test", e);
}
}
}
@Test
public void testResourceNotAvailableInPolicy() {
Map<String, Map<AtlasResourceTypes, List<String>>> userReadMap = null;
Map<String, Map<AtlasResourceTypes, List<String>>> groupReadMap = null;
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;type:PII");
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
PolicyUtil policyUtil = new PolicyUtil();
// group read map
groupReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
// creating user readMap
userReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.USER);
Set<AtlasResourceTypes> resourceType = new HashSet<>();
resourceType.add(AtlasResourceTypes.TYPE);
String resource = "abc";
AtlasActionTypes action = AtlasActionTypes.READ;
String user = "usr1";
Set<String> userGroups = new HashSet<>();
userGroups.add("grp1");
AtlasAccessRequest request = new AtlasAccessRequest(resourceType,
resource, action, user, userGroups,"127.0.0.1");
try {
SimpleAtlasAuthorizer authorizer = (SimpleAtlasAuthorizer) AtlasAuthorizerFactory
.getAtlasAuthorizer();
authorizer
.setResourcesForTesting(userReadMap, groupReadMap, action);
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(false, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("AtlasAuthorizationException in Unit Test", e);
}
}
}
@Test
public void testAccessNotAllowedForUserAndGroup() {
Map<String, Map<AtlasResourceTypes, List<String>>> userReadMap = null;
Map<String, Map<AtlasResourceTypes, List<String>>> groupReadMap = null;
List<String> policies = new ArrayList<>();
policies.add("hivePolicy;;usr1:r,usr2:rw;;grp1:rwu,grp2:u;;type:PII");
List<PolicyDef> policyDefs = new PolicyParser().parsePolicies(policies);
PolicyUtil policyUtil = new PolicyUtil();
// group read map
groupReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.GROUP);
// creating user readMap
userReadMap = policyUtil.createPermissionMap(policyDefs,
AtlasActionTypes.READ, SimpleAtlasAuthorizer.AtlasAccessorTypes.USER);
Set<AtlasResourceTypes> resourceType = new HashSet<>();
resourceType.add(AtlasResourceTypes.TYPE);
String resource = "PII";
AtlasActionTypes action = AtlasActionTypes.READ;
String user = "usr3";
Set<String> userGroups = new HashSet<>();
userGroups.add("grp3");
AtlasAccessRequest request = new AtlasAccessRequest(resourceType,
resource, action, user, userGroups,"127.0.0.1");
try {
SimpleAtlasAuthorizer authorizer = (SimpleAtlasAuthorizer) AtlasAuthorizerFactory
.getAtlasAuthorizer();
authorizer
.setResourcesForTesting(userReadMap, groupReadMap, action);
boolean isAccessAllowed = authorizer.isAccessAllowed(request);
AssertJUnit.assertEquals(false, isAccessAllowed);
} catch (AtlasAuthorizationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("AtlasAuthorizationException in Unit Test", e);
}
}
}
}
#
# 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.
#
#system property
atlas.data=${sys:user.dir}/target/data
#re-use existing property
atlas.graph.data=${atlas.data}/graph
#plain property
atlas.service=atlas
#invalid system property
atlas.db=${atlasdb}
atlas.TypeSystem.impl=org.apache.atlas.typesystem.types.TypeSystem
######### Atlas Server Configs #########
atlas.rest.address=http://localhost:31000
######### Graph Database Configs #########
# Graph database implementation. Value inserted by maven.
atlas.graphdb.backend=${graphdb.backend.impl}
# Graph Storage
atlas.graph.storage.backend=${graph.storage.backend}
# Entity repository implementation
atlas.EntityAuditRepository.impl=${entity.repository.impl}
# Graph Search Index Backend
atlas.graph.index.search.backend=${graph.index.backend}
#Berkeley storage directory
atlas.graph.storage.directory=${sys:atlas.data}/berkley
#hbase
#For standalone mode , specify localhost
#for distributed mode, specify zookeeper quorum here - For more information refer http://s3.thinkaurelius.com/docs/titan/current/hbase.html#_remote_server_mode_2
atlas.graph.storage.hostname=${graph.storage.hostname}
atlas.graph.storage.hbase.regions-per-server=1
atlas.graph.storage.lock.wait-time=10000
#ElasticSearch
atlas.graph.index.search.directory=${sys:atlas.data}/es
atlas.graph.index.search.elasticsearch.client-only=false
atlas.graph.index.search.elasticsearch.local-mode=true
atlas.graph.index.search.elasticsearch.create.sleep=2000
# Solr cloud mode properties
atlas.graph.index.search.solr.mode=cloud
atlas.graph.index.search.solr.zookeeper-url=${solr.zk.address}
atlas.graph.index.search.solr.embedded=${tests.solr.embedded}
atlas.graph.index.search.max-result-set-size=150
######### Hive Lineage Configs #########
## Schema
atlas.lineage.schema.query.hive_table=hive_table where __guid='%s'\, columns
atlas.lineage.schema.query.hive_table_v1=hive_table_v1 where __guid='%s'\, columns
######### Notification Configs #########
atlas.notification.embedded=true
atlas.kafka.zookeeper.connect=localhost:19026
atlas.kafka.bootstrap.servers=localhost:19027
atlas.kafka.data=${sys:atlas.data}/kafka
atlas.kafka.zookeeper.session.timeout.ms=4000
atlas.kafka.zookeeper.sync.time.ms=20
atlas.kafka.consumer.timeout.ms=4000
atlas.kafka.auto.commit.interval.ms=100
atlas.kafka.hook.group.id=atlas
atlas.kafka.entities.group.id=atlas_entities
#atlas.kafka.auto.commit.enable=false
atlas.kafka.enable.auto.commit=false
atlas.kafka.auto.offset.reset=earliest
atlas.kafka.session.timeout.ms=30000
######### Entity Audit Configs #########
atlas.audit.hbase.tablename=ATLAS_ENTITY_AUDIT_EVENTS
atlas.audit.zookeeper.session.timeout.ms=1000
atlas.audit.hbase.zookeeper.quorum=localhost
atlas.audit.hbase.zookeeper.property.clientPort=19026
######### Security Properties #########
# SSL config
atlas.enableTLS=false
atlas.server.https.port=31443
######### Security Properties #########
hbase.security.authentication=simple
atlas.hook.falcon.synchronous=true
######### JAAS Configuration ########
atlas.jaas.KafkaClient.loginModuleName = com.sun.security.auth.module.Krb5LoginModule
atlas.jaas.KafkaClient.loginModuleControlFlag = required
atlas.jaas.KafkaClient.option.useKeyTab = true
atlas.jaas.KafkaClient.option.storeKey = true
atlas.jaas.KafkaClient.option.serviceName = kafka
atlas.jaas.KafkaClient.option.keyTab = /etc/security/keytabs/atlas.service.keytab
atlas.jaas.KafkaClient.option.principal = atlas/_HOST@EXAMPLE.COM
######### High Availability Configuration ########
atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
######### Atlas Authorization #########
#atlas.authorizer.impl=none
atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
######### Gremlin Search Configuration #########
# Set to false to disable gremlin search.
atlas.search.gremlin.enable=true
{
"roles": {
"ROLE_ADMIN": {
"adminPermissions": [
{
"privileges": [ ".*" ]
}
],
"entityPermissions": [
{
"privileges": [ ".*" ],
"entityTypes": [ ".*" ],
"entityIds": [ ".*" ],
"classifications": [ ".*" ]
}
],
"typePermissions": [
{
"privileges": [ ".*" ],
"typeCategories": [ ".*" ],
"typeNames": [ ".*" ]
}
]
},
"DATA_SCIENTIST": {
"entityPermissions": [
{
"privileges": [ "entity-read", "entity-read-classification" ],
"entityTypes": [ ".*" ],
"entityIds": [ ".*" ],
"classifications": [ ".*" ]
}
]
},
"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": [ ".*" ]
}
]
}
},
"userRoles": {
"admin": [ "ROLE_ADMIN" ]
},
"groupRoles": {
"ROLE_ADMIN": [ "ROLE_ADMIN" ],
"hadoop": [ "DATA_STEWARD" ],
"DATA_STEWARD": [ "DATA_STEWARD" ],
"RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ]
}
}
......@@ -184,8 +184,9 @@ atlas.server.ha.enabled=false
#########POLICY FILE PATH #########
atlas.auth.policy.file=${sys:atlas.home}/conf/policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=simple
atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Type Cache Implementation ########
# A type cache class which implements
......@@ -193,9 +194,6 @@ atlas.auth.policy.file=${sys:atlas.home}/conf/policy-store.txt
# The default implementation is org.apache.atlas.typesystem.types.cache.DefaultTypeCache which is a local in-memory type cache.
#atlas.TypeCache.impl=
#########authorizer impl class #########
atlas.authorizer.impl=SIMPLE
######### Performance Configs #########
#atlas.graph.storage.lock.retries=10
#atlas.graph.storage.cache.db-cache-time=120000
......
......@@ -174,57 +174,57 @@ public final class ApplicationProperties extends PropertiesConfiguration {
* @throws AtlasException if no file was found or if there was an error loading the file
*/
public static InputStream getFileAsInputStream(Configuration configuration, String propertyName, String defaultFileName) throws AtlasException {
File fileToLoad = null;
String fileName = configuration.getString(propertyName);
File fileToLoad = null;
String fileName = configuration.getString(propertyName);
if (fileName == null) {
if (defaultFileName == null) {
throw new AtlasException(propertyName + " property not set and no default value specified");
}
LOG.info("{} property not set; defaulting to {}", propertyName, defaultFileName);
fileName = defaultFileName;
String atlasConfDir = System.getProperty(ATLAS_CONFIGURATION_DIRECTORY_PROPERTY);
if (atlasConfDir != null) {
// Look for default filename in Atlas config directory
fileToLoad = new File(atlasConfDir, fileName);
}
else {
} else {
// Look for default filename under the working directory
fileToLoad = new File(fileName);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} property not set - defaulting to {}", propertyName, fileToLoad.getPath());
}
}
else {
} else {
// Look for configured filename
fileToLoad = new File(fileName);
if (LOG.isDebugEnabled()) {
LOG.debug("Using {} property setting: {}", propertyName, fileToLoad.getPath());
}
}
InputStream inStr = null;
if (fileToLoad.exists()) {
try {
LOG.info("Loading file {} from {}", fileName, fileToLoad.getPath());
inStr = new FileInputStream(fileToLoad);
} catch (FileNotFoundException e) {
throw new AtlasException("Error loading file " + fileName, e);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded file from : {}", fileToLoad.getPath());
}
}
else {
} else {
// Look for file as class loader resource
inStr = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
if (inStr == null) {
String msg = fileName + " not found in file system or as class loader resource";
LOG.error(msg);
throw new AtlasException(msg);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded {} as resource from : {}", fileName, Thread.currentThread().getContextClassLoader().getResource(fileName).toString());
}
LOG.info("Loaded {} as resource from {}", fileName, Thread.currentThread().getContextClassLoader().getResource(fileName).toString());
}
return inStr;
}
......
......@@ -126,6 +126,8 @@ public enum AtlasErrorCode {
CLASSIFICATION_DELETE_FROM_PROPAGATED_ENTITY(400, "ATLAS-400-00-06C", "Delete of classification {0} is not allowed from propagated entity"),
CLASSIFICATION_NOT_ASSOCIATED_WITH_ENTITY(400, "ATLAS-400-00-06D", "Classification {0} is not associated with entity"),
UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to perform {1}"),
// All Not found enums go here
TYPE_NAME_NOT_FOUND(404, "ATLAS-404-00-001", "Given typename {0} was invalid"),
TYPE_GUID_NOT_FOUND(404, "ATLAS-404-00-002", "Given type guid {0} was invalid"),
......@@ -142,6 +144,7 @@ public enum AtlasErrorCode {
RELATIONSHIPDEF_END_TYPE_NAME_NOT_FOUND(404, "ATLAS-404-00-00E", "RelationshipDef {0} endDef typename {0} cannot be found"),
RELATIONSHIP_ALREADY_DELETED(404, "ATLAS-404-00-00F", "Attempting to delete a relationship which is already deleted : {0}"),
INVALID_ENTITY_GUID_FOR_CLASSIFICATION_UPDATE(404, "ATLAS-404-00-010", "Updating entityGuid of classification is not allowed."),
INSTANCE_GUID_NOT_DATASET(404, "ATLAS-404-00-011", "Given instance guid {0} is not a dataset"),
// All data conflict errors go here
TYPE_ALREADY_EXISTS(409, "ATLAS-409-00-001", "Given type {0} already exists"),
......
......@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
......@@ -36,6 +37,7 @@ import org.apache.atlas.model.PList;
import org.apache.atlas.model.SearchFilter.SortType;
import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.commons.collections.CollectionUtils;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
......@@ -98,6 +100,20 @@ public class AtlasEntityHeader extends AtlasStruct implements Serializable {
}
}
public AtlasEntityHeader(AtlasEntity entity){
super(entity.getTypeName(), entity.getAttributes());
setGuid(entity.getGuid());
setClassifications(entity.getClassifications());
if (CollectionUtils.isNotEmpty(entity.getClassifications())) {
this.classificationNames = new ArrayList<>(entity.getClassifications().size());
for (AtlasClassification classification : entity.getClassifications()) {
this.classificationNames.add(classification.getTypeName());
}
}
}
public String getGuid() {
return guid;
}
......
......@@ -45,6 +45,7 @@ public class AtlasClassificationType extends AtlasStructType {
private Set<String> subTypes = Collections.emptySet();
private Set<String> allSubTypes = Collections.emptySet();
private Set<String> typeAndAllSubTypes = Collections.emptySet();
private Set<String> typeAndAllSuperTypes = Collections.emptySet();
private String typeAndAllSubTypesQryStr = "";
// we need to store the entityTypes specified in our supertypes. i.e. our parent classificationDefs may specify more entityTypes
......@@ -113,6 +114,10 @@ public class AtlasClassificationType extends AtlasStructType {
this.entityTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase3()
this.typeAndAllSubTypes.add(this.getTypeName());
this.typeAndAllSuperTypes = new HashSet<>(this.allSuperTypes);
this.typeAndAllSuperTypes.add(this.getTypeName());
this.typeAndAllSuperTypes = Collections.unmodifiableSet(this.typeAndAllSuperTypes);
}
@Override
......@@ -241,6 +246,8 @@ public class AtlasClassificationType extends AtlasStructType {
public Set<String> getTypeAndAllSubTypes() { return typeAndAllSubTypes; }
public Set<String> getTypeAndAllSuperTypes() { return typeAndAllSuperTypes; }
public String getTypeQryStr() { return typeQryStr; }
public String getTypeAndAllSubTypesQryStr() {
......
......@@ -46,6 +46,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
......@@ -156,6 +157,20 @@ public class AtlasJson {
return ret;
}
public static <T> T fromJson(InputStream inputStream, Class<T> type) throws IOException {
T ret = null;
if (inputStream != null) {
ret = mapper.readValue(inputStream, type);
if (ret instanceof Struct) {
((Struct) ret).normalize();
}
}
return ret;
}
public static String toV1Json(Object obj) {
return toJson(obj);
}
......
......@@ -133,14 +133,17 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
######### Gremlin Search Configuration #########
# Set to false to disable gremlin search.
atlas.search.gremlin.enable=true
\ No newline at end of file
atlas.search.gremlin.enable=true
......@@ -112,6 +112,12 @@
<type>pom</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
<artifactId>atlas-authorization</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.atlas</groupId>
......
......@@ -22,15 +22,17 @@ package org.apache.atlas.discovery;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.annotation.GraphTransaction;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.authorize.AtlasEntityAccessRequest;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.lineage.AtlasLineageInfo;
import org.apache.atlas.model.lineage.AtlasLineageInfo.LineageDirection;
import org.apache.atlas.model.lineage.AtlasLineageInfo.LineageRelation;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.graph.GraphHelper;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1;
......@@ -80,8 +82,14 @@ public class EntityLineageService implements AtlasLineageService {
public AtlasLineageInfo getAtlasLineageInfo(String guid, LineageDirection direction, int depth) throws AtlasBaseException {
AtlasLineageInfo lineageInfo;
if (!entityExists(guid)) {
throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid);
AtlasEntityHeader entity = entityRetriever.toAtlasEntityHeaderWithClassifications(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(atlasTypeRegistry, AtlasPrivilege.ENTITY_READ, entity), "read entity lineage: guid=", guid);
AtlasEntityType entityType = atlasTypeRegistry.getEntityTypeByName(entity.getTypeName());
if (entityType == null || !entityType.getTypeAndAllSuperTypes().contains(AtlasClient.DATA_SET_SUPER_TYPE)) {
throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_DATASET, guid);
}
if (direction != null) {
......@@ -129,10 +137,14 @@ public class EntityLineageService implements AtlasLineageService {
ret.setDataType(AtlasTypeUtil.toClassTypeDefinition(hive_column));
AtlasEntity.AtlasEntityWithExtInfo entityWithExtInfo = entityRetriever.toAtlasEntityWithExtInfo(guid);
AtlasEntity entity = entityWithExtInfo.getEntity();
Map<String, AtlasEntity> referredEntities = entityWithExtInfo.getReferredEntities();
List<String> columnIds = getColumnIds(entity);
AtlasEntityWithExtInfo entityWithExtInfo = entityRetriever.toAtlasEntityWithExtInfo(guid);
AtlasEntity entity = entityWithExtInfo.getEntity();
AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(atlasTypeRegistry, AtlasPrivilege.ENTITY_READ, new AtlasEntityHeader(entity)),
"read entity schema: guid=", guid);
Map<String, AtlasEntity> referredEntities = entityWithExtInfo.getReferredEntities();
List<String> columnIds = getColumnIds(entity);
if (MapUtils.isNotEmpty(referredEntities)) {
List<Map<String, Object>> rows = referredEntities.entrySet()
......@@ -244,21 +256,4 @@ public class EntityLineageService implements AtlasLineageService {
}
return lineageQuery;
}
private boolean entityExists(String guid) {
boolean ret = false;
Iterator<AtlasVertex> results = graph.query()
.has(Constants.GUID_PROPERTY_KEY, guid)
.vertices().iterator();
while (results.hasNext()) {
AtlasVertex entityVertex = results.next();
List<String> superTypes = GraphHelper.getSuperTypeNames(entityVertex);
ret = (CollectionUtils.isNotEmpty(superTypes)) && superTypes.contains(AtlasClient.DATA_SET_SUPER_TYPE);
}
return ret;
}
}
\ No newline at end of file
......@@ -19,6 +19,9 @@ package org.apache.atlas.repository.store.graph.v1;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.authorize.AtlasTypeAccessRequest;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.typedef.AtlasClassificationDef;
import org.apache.atlas.repository.Constants;
......@@ -83,12 +86,13 @@ class AtlasClassificationDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasClassif
}
@Override
public AtlasClassificationDef create(AtlasClassificationDef classificationDef, AtlasVertex preCreateResult)
throws AtlasBaseException {
public AtlasClassificationDef create(AtlasClassificationDef classificationDef, AtlasVertex preCreateResult) throws AtlasBaseException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> AtlasClassificationDefStoreV1.create({}, {})", classificationDef, preCreateResult);
}
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_CREATE, classificationDef), "create classification-def ", classificationDef.getName());
AtlasVertex vertex = (preCreateResult == null) ? preCreate(classificationDef) : preCreateResult;
updateVertexAddReferences(classificationDef, vertex);
......@@ -190,6 +194,10 @@ class AtlasClassificationDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasClassif
LOG.debug("==> AtlasClassificationDefStoreV1.updateByName({}, {})", name, classificationDef);
}
AtlasClassificationDef existingDef = typeRegistry.getClassificationDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update classification-def ", name);
validateType(classificationDef);
AtlasType type = typeRegistry.getType(classificationDef.getName());
......@@ -222,6 +230,10 @@ class AtlasClassificationDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasClassif
LOG.debug("==> AtlasClassificationDefStoreV1.updateByGuid({})", guid);
}
AtlasClassificationDef existingDef = typeRegistry.getClassificationDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update classification-def ", (existingDef != null ? existingDef.getName() : guid));
validateType(classificationDef);
AtlasType type = typeRegistry.getTypeByGuid(guid);
......@@ -254,6 +266,10 @@ class AtlasClassificationDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasClassif
LOG.debug("==> AtlasClassificationDefStoreV1.preDeleteByName({})", name);
}
AtlasClassificationDef existingDef = typeRegistry.getClassificationDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete classification-def ", name);
AtlasVertex ret = typeDefStore.findTypeVertexByNameAndCategory(name, TypeCategory.TRAIT);
if (AtlasGraphUtilsV1.typeHasInstanceVertex(name)) {
......@@ -279,6 +295,10 @@ class AtlasClassificationDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasClassif
LOG.debug("==> AtlasClassificationDefStoreV1.preDeleteByGuid({})", guid);
}
AtlasClassificationDef existingDef = typeRegistry.getClassificationDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete classification-def ", (existingDef != null ? existingDef.getName() : guid));
AtlasVertex ret = typeDefStore.findTypeVertexByGuidAndCategory(guid, TypeCategory.TRAIT);
String typeName = AtlasGraphUtilsV1.getProperty(ret, Constants.TYPENAME_PROPERTY_KEY, String.class);
......
......@@ -18,6 +18,9 @@
package org.apache.atlas.repository.store.graph.v1;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.authorize.AtlasTypeAccessRequest;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.repository.Constants;
......@@ -60,6 +63,8 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
throw new AtlasBaseException(AtlasErrorCode.TYPE_MATCH_FAILED, entityDef.getName(), TypeCategory.CLASS.name());
}
AtlasVertex ret = typeDefStore.findTypeVertexByName(entityDef.getName());
if (ret != null) {
......@@ -83,6 +88,8 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
LOG.debug("==> AtlasEntityDefStoreV1.create({}, {})", entityDef, preCreateResult);
}
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_CREATE, entityDef), "create entity-def ", entityDef.getName());
AtlasVertex vertex = (preCreateResult == null) ? preCreate(entityDef) : preCreateResult;
updateVertexAddReferences(entityDef, vertex);
......@@ -184,6 +191,10 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
LOG.debug("==> AtlasEntityDefStoreV1.updateByName({}, {})", name, entityDef);
}
AtlasEntityDef existingDef = typeRegistry.getEntityDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update entity-def ", name);
validateType(entityDef);
AtlasType type = typeRegistry.getType(entityDef.getName());
......@@ -216,6 +227,10 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
LOG.debug("==> AtlasEntityDefStoreV1.updateByGuid({})", guid);
}
AtlasEntityDef existingDef = typeRegistry.getEntityDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update entity-def ", (existingDef != null ? existingDef.getName() : guid));
validateType(entityDef);
AtlasType type = typeRegistry.getTypeByGuid(guid);
......@@ -248,6 +263,10 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
LOG.debug("==> AtlasEntityDefStoreV1.preDeleteByName({})", name);
}
AtlasEntityDef existingDef = typeRegistry.getEntityDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete entity-def ", name);
AtlasVertex ret = typeDefStore.findTypeVertexByNameAndCategory(name, TypeCategory.CLASS);
if (AtlasGraphUtilsV1.typeHasInstanceVertex(name)) {
......@@ -278,6 +297,10 @@ public class AtlasEntityDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasEntityDe
LOG.debug("==> AtlasEntityDefStoreV1.preDeleteByGuid({})", guid);
}
AtlasEntityDef existingDef = typeRegistry.getEntityDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete entity-def ", (existingDef != null ? existingDef.getName() : guid));
AtlasVertex ret = typeDefStore.findTypeVertexByGuidAndCategory(guid, TypeCategory.CLASS);
String typeName = AtlasGraphUtilsV1.getProperty(ret, Constants.TYPENAME_PROPERTY_KEY, String.class);
......
......@@ -19,6 +19,9 @@ package org.apache.atlas.repository.store.graph.v1;
import com.google.common.annotations.VisibleForTesting;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.authorize.AtlasTypeAccessRequest;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.typedef.AtlasStructDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
......@@ -93,12 +96,14 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasStructDe
LOG.debug("==> AtlasStructDefStoreV1.create({}, {})", structDef, preCreateResult);
}
AtlasVertex vertex = (preCreateResult == null) ? preCreate(structDef) : preCreateResult;
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_CREATE, structDef), "create struct-def ", structDef.getName());
if (CollectionUtils.isEmpty(structDef.getAttributeDefs())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Missing attributes for structdef");
}
AtlasVertex vertex = (preCreateResult == null) ? preCreate(structDef) : preCreateResult;
AtlasStructDefStoreV1.updateVertexAddReferences(structDef, vertex, typeDefStore);
AtlasStructDef ret = toStructDef(vertex);
......@@ -197,6 +202,10 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasStructDe
LOG.debug("==> AtlasStructDefStoreV1.updateByName({}, {})", name, structDef);
}
AtlasStructDef existingDef = typeRegistry.getStructDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update struct-def ", name);
validateType(structDef);
AtlasType type = typeRegistry.getType(structDef.getName());
......@@ -229,6 +238,10 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasStructDe
LOG.debug("==> AtlasStructDefStoreV1.updateByGuid({})", guid);
}
AtlasStructDef existingDef = typeRegistry.getStructDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_UPDATE, existingDef), "update struct-def ", (existingDef != null ? existingDef.getName() : guid));
validateType(structDef);
AtlasType type = typeRegistry.getTypeByGuid(guid);
......@@ -261,6 +274,10 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasStructDe
LOG.debug("==> AtlasStructDefStoreV1.preDeleteByName({})", name);
}
AtlasStructDef existingDef = typeRegistry.getStructDefByName(name);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete struct-def ", name);
AtlasVertex ret = typeDefStore.findTypeVertexByNameAndCategory(name, TypeCategory.STRUCT);
if (AtlasGraphUtilsV1.typeHasInstanceVertex(name)) {
......@@ -286,6 +303,10 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1<AtlasStructDe
LOG.debug("==> AtlasStructDefStoreV1.preDeleteByGuid({})", guid);
}
AtlasStructDef existingDef = typeRegistry.getStructDefByGuid(guid);
AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_DELETE, existingDef), "delete struct-def ", (existingDef != null ? existingDef.getName() : guid));
AtlasVertex ret = typeDefStore.findTypeVertexByGuidAndCategory(guid, TypeCategory.STRUCT);
String typeName = AtlasGraphUtilsV1.getProperty(ret, Constants.TYPENAME_PROPERTY_KEY, String.class);
......
......@@ -170,6 +170,22 @@ public final class EntityGraphRetriever {
return atlasVertex != null ? mapVertexToAtlasEntityHeader(atlasVertex, attributes) : null;
}
public AtlasEntityHeader toAtlasEntityHeaderWithClassifications(String guid) throws AtlasBaseException {
return toAtlasEntityHeaderWithClassifications(getEntityVertex(guid), Collections.emptySet());
}
public AtlasEntityHeader toAtlasEntityHeaderWithClassifications(AtlasVertex entityVertex) throws AtlasBaseException {
return toAtlasEntityHeaderWithClassifications(entityVertex, Collections.emptySet());
}
public AtlasEntityHeader toAtlasEntityHeaderWithClassifications(AtlasVertex entityVertex, Set<String> attributes) throws AtlasBaseException {
AtlasEntityHeader ret = toAtlasEntityHeader(entityVertex, attributes);
ret.setClassifications(getClassifications(entityVertex));
return ret;
}
public AtlasEntityHeader toAtlasEntityHeader(AtlasEntity entity) {
AtlasEntityHeader ret = null;
String typeName = entity.getTypeName();
......@@ -187,6 +203,19 @@ public final class EntityGraphRetriever {
}
ret = new AtlasEntityHeader(entity.getTypeName(), entity.getGuid(), uniqueAttributes);
if (CollectionUtils.isNotEmpty(entity.getClassifications())) {
List<AtlasClassification> classifications = new ArrayList<>(entity.getClassifications().size());
List<String> classificationNames = new ArrayList<>(entity.getClassifications().size());
for (AtlasClassification classification : entity.getClassifications()) {
classifications.add(classification);
classificationNames.add(classification.getTypeName());
}
ret.setClassifications(classifications);
ret.setClassificationNames(classificationNames);
}
}
return ret;
......@@ -218,7 +247,7 @@ public final class EntityGraphRetriever {
AtlasClassification ret = new AtlasClassification(getTypeName(classificationVertex));
ret.setEntityGuid(AtlasGraphUtilsV1.getProperty(classificationVertex, CLASSIFICATION_ENTITY_GUID, String.class));
ret.setPropagate(AtlasGraphUtilsV1.getProperty(classificationVertex, CLASSIFICATION_PROPAGATE_KEY, Boolean.class));
ret.setPropagate(isPropagationEnabled(classificationVertex));
String strValidityPeriods = AtlasGraphUtilsV1.getProperty(classificationVertex, CLASSIFICATION_VALIDITY_PERIODS_KEY, String.class);
......
......@@ -173,30 +173,32 @@ public class AtlasRepositoryConfiguration {
* @throws AtlasException
*/
public static List<String> getAuditExcludedOperations(Configuration config) throws AtlasException {
if (config == null) {
try {
config = ApplicationProperties.get();
} catch (AtlasException e) {
LOG.error(" Error reading operations for auditing ", e);
throw e;
}
}
if (skippedOperations == null) {
skippedOperations = new ArrayList<String>();
String[] skipAuditForOperations = config
.getStringArray(AUDIT_EXCLUDED_OPERATIONS);
if (skipAuditForOperations != null
&& skipAuditForOperations.length > 0) {
for (String skippedOperation : skipAuditForOperations) {
String[] excludedOperations = skippedOperation.trim().toLowerCase().split(SEPARATOR);
if (excludedOperations!= null && excludedOperations.length == 2) {
skippedOperations.add(skippedOperation.toLowerCase());
} else {
LOG.error("Invalid format for skipped operation {}. Valid format is HttpMethod:URL eg: GET:Version", skippedOperation);
}
if (config == null) {
try {
config = ApplicationProperties.get();
} catch (AtlasException e) {
LOG.error(" Error reading operations for auditing ", e);
throw e;
}
}
skippedOperations = new ArrayList<>();
String[] skipAuditForOperations = config.getStringArray(AUDIT_EXCLUDED_OPERATIONS);
if (skipAuditForOperations != null && skipAuditForOperations.length > 0) {
for (String skippedOperation : skipAuditForOperations) {
String[] excludedOperations = skippedOperation.trim().toLowerCase().split(SEPARATOR);
if (excludedOperations!= null && excludedOperations.length == 2) {
skippedOperations.add(skippedOperation.toLowerCase());
} else {
LOG.error("Invalid format for skipped operation {}. Valid format is HttpMethod:URL eg: GET:Version", skippedOperation);
}
}
}
}
return skippedOperations;
}
......
......@@ -85,7 +85,7 @@ public class ExportServiceTest {
@BeforeTest
public void setupTest() {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@BeforeClass
......
......@@ -70,7 +70,7 @@ public class ImportServiceTest {
@BeforeTest
public void setupTest() {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@AfterClass
......
......@@ -208,7 +208,7 @@ public class ZipFileResourceTestUtils {
List<String> creationOrder = zipSource.getCreationOrder();
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
AtlasImportRequest request = getDefaultImportRequest();
AtlasImportResult result = runImportWithParameters(importService, request, zipSource);
......
......@@ -57,7 +57,7 @@ public class AtlasTypeDefGraphStoreTest {
@BeforeTest
public void setupTest() {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@AfterClass
......
......@@ -111,7 +111,7 @@ public class AtlasEntityStoreV1Test {
@BeforeClass
public void setUp() throws Exception {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
new GraphBackedSearchIndexer(typeRegistry);
......@@ -156,7 +156,7 @@ public class AtlasEntityStoreV1Test {
public void init() throws Exception {
entityStore = new AtlasEntityStoreV1(deleteHandler, typeRegistry, mockChangeNotifier, graphMapper);
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@Test
......
......@@ -118,7 +118,7 @@ public abstract class AtlasRelationshipStoreV1Test {
relationshipStore = new AtlasRelationshipStoreV1(typeRegistry, deleteHandler);
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@AfterClass
......
......@@ -75,7 +75,7 @@ public abstract class InverseReferenceUpdateV1Test {
@BeforeClass
public void setUp() throws Exception {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { TestUtilsV2.defineDeptEmployeeTypes(),
TestUtilsV2.defineInverseReferenceTestTypes()
......@@ -109,7 +109,7 @@ public abstract class InverseReferenceUpdateV1Test {
@BeforeMethod
public void init() throws Exception {
RequestContextV1.clear();
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
RequestContextV1.get().setUser(TestUtilsV2.TEST_USER, null);
}
@Test
......
......@@ -18,7 +18,6 @@
package org.apache.atlas;
import org.apache.atlas.metrics.Metrics;
import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.slf4j.Logger;
......@@ -34,10 +33,10 @@ public class RequestContextV1 {
private final Map<String, AtlasObjectId> updatedEntities = new HashMap<>();
private final Map<String, AtlasObjectId> deletedEntities = new HashMap<>();
private final Map<String, AtlasEntityWithExtInfo> entityCacheV2 = new HashMap<>();
private final Metrics metrics = new Metrics();
private final long requestTime = System.currentTimeMillis();
private String user;
private String user;
private Set<String> userGroups;
private RequestContextV1() {
}
......@@ -71,8 +70,13 @@ public class RequestContextV1 {
return user;
}
public void setUser(String user) {
this.user = user;
public Set<String> getUserGroups() {
return userGroups;
}
public void setUser(String user, Set<String> userGroups) {
this.user = user;
this.userGroups = userGroups;
}
public void recordEntityUpdate(AtlasObjectId entity) {
......@@ -127,8 +131,4 @@ public class RequestContextV1 {
public boolean isDeletedEntity(String guid) {
return deletedEntities.containsKey(guid);
}
public static Metrics getMetrics() {
return get().metrics;
}
}
/**
* 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.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
}
\ No newline at end of file
/**
* 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.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Monitored {
}
\ No newline at end of file
/**
* 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.discovery;
import org.apache.atlas.AtlasException;
import java.security.PrivilegedActionException;
public class DiscoveryException extends AtlasException {
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public DiscoveryException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public DiscoveryException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new exception with the specified cause and a detail
* message of <tt>(cause==null ? null : cause.toString())</tt> (which
* typically contains the class and detail message of <tt>cause</tt>).
* This constructor is useful for exceptions that are little more than
* wrappers for other throwables (for example, {@link
* PrivilegedActionException}).
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public DiscoveryException(Throwable cause) {
super(cause);
}
}
/**
* 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.metrics;
import java.util.LinkedHashMap;
import java.util.Map;
public class Metrics {
public static class Counters {
private short invocations = 0;
private long totalTimeMSecs = 0;
@Override
public String toString() {
return "[count=" + invocations + ", totalTimeMSec=" + totalTimeMSecs + "]";
}
public short getInvocations() {
return invocations;
}
public long getTotalTimeMSecs() {
return totalTimeMSecs;
}
}
Map<String, Counters> countersMap = new LinkedHashMap<>();
public void record(String name, long timeMsecs) {
Counters counter = countersMap.get(name);
if (counter == null) {
counter = new Counters();
countersMap.put(name, counter);
}
counter.invocations++;
counter.totalTimeMSecs += timeMsecs;
}
@Override
public String toString() {
return countersMap.toString();
}
public boolean isEmpty() {
return countersMap.isEmpty();
}
public Counters getCounters(String name) {
return countersMap.get(name);
}
}
......@@ -328,10 +328,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
try {
String requestUser = httpRequest.getRemoteUser();
NDC.push(requestUser + ":" + httpRequest.getMethod() + httpRequest.getRequestURI());
RequestContextV1 requestContext = RequestContextV1.get();
if (requestContext != null) {
requestContext.setUser(requestUser);
}
LOG.info("Request from authenticated user: {}, URL={}", requestUser,
Servlets.getRequestURI(httpRequest));
......
/*
* 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.web.filters;
import com.google.common.base.Strings;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.authorize.AtlasAccessRequest;
import org.apache.atlas.authorize.AtlasAuthorizationException;
import org.apache.atlas.authorize.AtlasAuthorizer;
import org.apache.atlas.authorize.AtlasAuthorizerFactory;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@Component
public class AtlasAuthorizationFilter extends GenericFilterBean {
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizationFilter.class);
private static boolean isDebugEnabled = LOG.isDebugEnabled();
private AtlasAuthorizer authorizer = null;
private final String BASE_URL = "/" + AtlasClient.BASE_URI;
public AtlasAuthorizationFilter() {
if (isDebugEnabled) {
LOG.debug("==> AtlasAuthorizationFilter() -- " + "Now initializing the Apache Atlas Authorizer!!!");
}
try {
authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer();
if (authorizer != null) {
authorizer.init();
} else {
LOG.warn("AtlasAuthorizer not initialized properly, please check the application logs and add proper configurations.");
}
} catch (AtlasAuthorizationException e) {
LOG.error("Unable to obtain AtlasAuthorizer. ", e);
}
}
@Override
public void destroy() {
if (isDebugEnabled) {
LOG.debug("==> AtlasAuthorizationFilter destroy");
}
if (authorizer != null) {
authorizer.cleanUp();
}
super.destroy();
}
@SuppressWarnings("unchecked")
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
if (isDebugEnabled) {
LOG.debug("==> AuthorizationFilter.doFilter");
}
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
AtlasResponseRequestWrapper responseWrapper = new AtlasResponseRequestWrapper(response);
responseWrapper.setHeader("X-Frame-Options", "DENY");
String pathInfo = request.getServletPath();
if (!Strings.isNullOrEmpty(pathInfo) && (pathInfo.startsWith(BASE_URL) || BASE_URL.startsWith(pathInfo))) {
if (isDebugEnabled) {
LOG.debug("{} is a valid REST API request!!!", pathInfo);
}
String userName = null;
Set<String> groups = new HashSet<>();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
userName = auth.getName();
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
for (GrantedAuthority c : authorities) {
groups.add(c.getAuthority());
}
} else {
if (LOG.isErrorEnabled()) {
LOG.error("Cannot obtain Security Context");
}
throw new ServletException("Cannot obtain Security Context");
}
AtlasAccessRequest atlasRequest = new AtlasAccessRequest(request, userName, groups);
if (isDebugEnabled) {
LOG.debug("============================\nUserName :: {}\nGroups :: {}\nURL :: {}\nAction :: {}\nrequest.getServletPath() :: {}\n============================\n", atlasRequest.getUser(), atlasRequest.getUserGroups(), request.getRequestURL(), atlasRequest.getAction(), pathInfo);
}
boolean accessAllowed = false;
Set<AtlasResourceTypes> atlasResourceTypes = atlasRequest.getResourceTypes();
if (atlasResourceTypes.size() == 1 && atlasResourceTypes.contains(AtlasResourceTypes.UNKNOWN)) {
// Allowing access to unprotected resource types
if (LOG.isDebugEnabled()) {
LOG.debug("Allowing access to unprotected resource types {}", atlasResourceTypes);
}
accessAllowed = true;
} else {
try {
if (authorizer != null) {
accessAllowed = authorizer.isAccessAllowed(atlasRequest);
}
} catch (AtlasAuthorizationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Access Restricted. Could not process the request :: {}", e);
}
}
if (isDebugEnabled) {
LOG.debug("Authorizer result :: {}", accessAllowed);
}
}
if (accessAllowed) {
if (isDebugEnabled) {
LOG.debug("Access is allowed so forwarding the request!!!");
}
chain.doFilter(req, res);
} else {
JSONObject json = new JSONObject();
json.put("AuthorizationError", "You are not authorized for " + atlasRequest.getAction().name() + " on "
+ atlasResourceTypes + " : " + atlasRequest.getResource());
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.sendError(HttpServletResponse.SC_FORBIDDEN, json.toString());
if (isDebugEnabled) {
LOG.debug("You are not authorized for {} on {} : {}\nReturning 403 since the access is blocked update!!!!", atlasRequest.getAction().name(), atlasResourceTypes, atlasRequest.getResource());
}
return;
}
} else {
if (isDebugEnabled) {
LOG.debug("Ignoring request {}", pathInfo);
}
chain.doFilter(req, res);
}
}
}
......@@ -21,7 +21,7 @@ package org.apache.atlas.web.filters;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RequestContextV1;
import org.apache.atlas.metrics.Metrics;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.util.AtlasRepositoryConfiguration;
import org.apache.atlas.web.util.DateTimeHelper;
import org.apache.atlas.web.util.Servlets;
......@@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
/**
......@@ -48,9 +49,8 @@ import java.util.UUID;
*/
@Component
public class AuditFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(AuditFilter.class);
private static final Logger AUDIT_LOG = LoggerFactory.getLogger("AUDIT");
private static final Logger LOG = LoggerFactory.getLogger(AuditFilter.class);
private static final Logger METRICS_LOG = LoggerFactory.getLogger("METRICS");
@Override
public void init(FilterConfig filterConfig) throws ServletException {
......@@ -60,25 +60,32 @@ public class AuditFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
final String requestTimeISO9601 = DateTimeHelper.formatDateUTC(new Date());
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final String requestId = UUID.randomUUID().toString();
final Thread currentThread = Thread.currentThread();
final String oldName = currentThread.getName();
String user = getUserFromRequest(httpRequest);
final long startTime = System.currentTimeMillis();
final Date requestTime = new Date();
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final HttpServletResponse httpResponse = (HttpServletResponse) response;
final String requestId = UUID.randomUUID().toString();
final Thread currentThread = Thread.currentThread();
final String oldName = currentThread.getName();
final String user = AtlasAuthorizationUtils.getCurrentUserName();
final Set<String> userGroups = AtlasAuthorizationUtils.getCurrentUserGroups();
try {
currentThread.setName(formatName(oldName, requestId));
RequestContextV1.clear();
RequestContextV1 requestContext = RequestContextV1.get();
requestContext.setUser(user);
recordAudit(httpRequest, requestTimeISO9601, user);
requestContext.setUser(user, userGroups);
filterChain.doFilter(request, response);
} finally {
long timeTaken = System.currentTimeMillis() - startTime;
recordAudit(httpRequest, requestTime, user, httpResponse.getStatus(), timeTaken);
// put the request id into the response so users can trace logs for this request
((HttpServletResponse) response).setHeader(AtlasClient.REQUEST_ID, requestId);
httpResponse.setHeader(AtlasClient.REQUEST_ID, requestId);
currentThread.setName(oldName);
recordMetrics();
RequestContextV1.clear();
}
}
......@@ -87,17 +94,14 @@ public class AuditFilter implements Filter {
return oldName + " - " + requestId;
}
private void recordAudit(HttpServletRequest httpRequest, String whenISO9601, String who) {
final String fromHost = httpRequest.getRemoteHost();
private void recordAudit(HttpServletRequest httpRequest, Date when, String who, int httpStatus, long timeTaken) {
final String fromAddress = httpRequest.getRemoteAddr();
final String whatRequest = httpRequest.getMethod();
final String whatURL = Servlets.getRequestURL(httpRequest);
final String whatAddrs = httpRequest.getLocalAddr();
final String whatUrlPath = httpRequest.getRequestURL().toString();//url path without query string
final String whatURL = Servlets.getRequestURL(httpRequest);
final String whatUrlPath = httpRequest.getRequestURL().toString(); //url path without query string
if (!isOperationExcludedFromAudit(whatRequest, whatUrlPath.toLowerCase(), null)) {
audit(who, fromAddress, whatRequest, fromHost, whatURL, whatAddrs, whenISO9601);
audit(new AuditLog(who, fromAddress, whatRequest, whatURL, when, httpStatus, timeTaken));
} else {
if(LOG.isDebugEnabled()) {
LOG.debug(" Skipping Audit for {} ", whatURL);
......@@ -105,25 +109,11 @@ public class AuditFilter implements Filter {
}
}
private String getUserFromRequest(HttpServletRequest httpRequest) {
// look for the user in the request
final String userFromRequest = Servlets.getUserFromRequest(httpRequest);
return userFromRequest == null ? "UNKNOWN" : userFromRequest;
}
public static void audit(String who, String fromAddress, String whatRequest, String fromHost, String whatURL, String whatAddrs,
String whenISO9601) {
AUDIT_LOG.info("Audit: {}/{}-{} performed request {} {} ({}) at time {}", who, fromAddress, fromHost, whatRequest, whatURL,
whatAddrs, whenISO9601);
}
public static void recordMetrics() {
//record metrics
Metrics requestMetrics = RequestContextV1.getMetrics();
if (!requestMetrics.isEmpty()) {
METRICS_LOG.info("{}", requestMetrics);
public static void audit(AuditLog auditLog) {
if (AUDIT_LOG.isInfoEnabled() && auditLog != null) {
AUDIT_LOG.info(auditLog.toString());
}
}
}
boolean isOperationExcludedFromAudit(String requestHttpMethod, String requestOperation, Configuration config) {
try {
......@@ -137,4 +127,53 @@ public class AuditFilter implements Filter {
public void destroy() {
// do nothing
}
public static class AuditLog {
private static final char FIELD_SEP = '|';
private final String userName;
private final String fromAddress;
private final String requestMethod;
private final String requestUrl;
private final Date requestTime;
private int httpStatus;
private long timeTaken;
public AuditLog(String userName, String fromAddress, String requestMethod, String requestUrl) {
this(userName, fromAddress, requestMethod, requestUrl, new Date());
}
public AuditLog(String userName, String fromAddress, String requestMethod, String requestUrl, Date requestTime) {
this(userName, fromAddress, requestMethod, requestUrl, requestTime, HttpServletResponse.SC_OK, 0);
}
public AuditLog(String userName, String fromAddress, String requestMethod, String requestUrl, Date requestTime, int httpStatus, long timeTaken) {
this.userName = userName;
this.fromAddress = fromAddress;
this.requestMethod = requestMethod;
this.requestUrl = requestUrl;
this.requestTime = requestTime;
this.httpStatus = httpStatus;
this.timeTaken = timeTaken;
}
public void setHttpStatus(int httpStatus) { this.httpStatus = httpStatus; }
public void setTimeTaken(long timeTaken) { this.timeTaken = timeTaken; }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(DateTimeHelper.formatDateUTC(requestTime))
.append(FIELD_SEP).append(userName)
.append(FIELD_SEP).append(fromAddress)
.append(FIELD_SEP).append(requestMethod)
.append(FIELD_SEP).append(requestUrl)
.append(FIELD_SEP).append(httpStatus)
.append(FIELD_SEP).append(timeTaken);
return sb.toString();
}
}
}
......@@ -22,9 +22,10 @@ import com.sun.jersey.multipart.FormDataParam;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.authorize.AtlasActionTypes;
import org.apache.atlas.authorize.AtlasResourceTypes;
import org.apache.atlas.authorize.simple.AtlasAuthorizationUtils;
import org.apache.atlas.authorize.AtlasAdminAccessRequest;
import org.apache.atlas.authorize.AtlasEntityAccessRequest;
import org.apache.atlas.authorize.AtlasPrivilege;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
import org.apache.atlas.discovery.SearchContext;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.impexp.AtlasExportRequest;
......@@ -38,6 +39,7 @@ import org.apache.atlas.repository.impexp.ZipSink;
import org.apache.atlas.repository.impexp.ZipSource;
import org.apache.atlas.services.MetricsService;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.util.SearchTracker;
import org.apache.atlas.utils.AtlasJson;
import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
......@@ -97,6 +99,8 @@ public class AdminResource {
@Context
private HttpServletResponse httpServletResponse;
private final AtlasTypeRegistry typeRegistry;
private final ReentrantLock importExportOperationLock;
private static final String isCSRF_ENABLED = "atlas.rest-csrf.enabled";
......@@ -126,12 +130,14 @@ public class AdminResource {
@Inject
public AdminResource(ServiceState serviceState, MetricsService metricsService,
ExportService exportService, ImportService importService, SearchTracker activeSearches) {
ExportService exportService, ImportService importService,
SearchTracker activeSearches, AtlasTypeRegistry typeRegistry) {
this.serviceState = serviceState;
this.metricsService = metricsService;
this.exportService = exportService;
this.importService = importService;
this.activeSearches = activeSearches;
this.typeRegistry = typeRegistry;
importExportOperationLock = new ReentrantLock();
}
......@@ -249,10 +255,8 @@ public class AdminResource {
groups.add(c.getAuthority());
}
isEntityUpdateAccessAllowed = AtlasAuthorizationUtils.isAccessAllowed(AtlasResourceTypes.ENTITY,
AtlasActionTypes.UPDATE, userName, groups, httpServletRequest);
isEntityCreateAccessAllowed = AtlasAuthorizationUtils.isAccessAllowed(AtlasResourceTypes.ENTITY,
AtlasActionTypes.CREATE, userName, groups, httpServletRequest);
isEntityUpdateAccessAllowed = AtlasAuthorizationUtils.isAccessAllowed(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE));
isEntityCreateAccessAllowed = AtlasAuthorizationUtils.isAccessAllowed(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_CREATE));
}
Map<String, Object> responseData = new HashMap<>();
......@@ -305,6 +309,8 @@ public class AdminResource {
LOG.debug("==> AdminResource.export()");
}
AtlasAuthorizationUtils.verifyAccess(new AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_EXPORT), "export");
acquireExportImportLock("export");
ZipSink exportSink = null;
......@@ -351,6 +357,8 @@ public class AdminResource {
LOG.debug("==> AdminResource.importData(jsonData={}, inputStream={})", jsonData, (inputStream != null));
}
AtlasAuthorizationUtils.verifyAccess(new AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "importData");
acquireExportImportLock("import");
AtlasImportResult result;
......@@ -384,6 +392,8 @@ public class AdminResource {
LOG.debug("==> AdminResource.importFile()");
}
AtlasAuthorizationUtils.verifyAccess(new AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "importFile");
acquireExportImportLock("importFile");
AtlasImportResult result;
......
......@@ -401,6 +401,8 @@ public class TypesREST {
AtlasTypeUtil.toDebugString(typesDef) + ")");
}
typeDefStore.deleteTypesDef(typesDef);
} finally {
AtlasPerfTracer.log(perf);
......
......@@ -20,7 +20,6 @@ package org.apache.atlas.web.security;
import org.apache.atlas.web.filters.ActiveServerFilter;
import org.apache.atlas.web.filters.AtlasAuthenticationEntryPoint;
import org.apache.atlas.web.filters.AtlasAuthenticationFilter;
import org.apache.atlas.web.filters.AtlasAuthorizationFilter;
import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
......@@ -35,7 +34,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
......@@ -54,7 +52,6 @@ public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
private final AtlasAuthenticationProvider authenticationProvider;
private final AtlasAuthenticationSuccessHandler successHandler;
private final AtlasAuthenticationFailureHandler failureHandler;
private final AtlasAuthorizationFilter atlasAuthorizationFilter;
private final AtlasKnoxSSOAuthenticationFilter ssoAuthenticationFilter;
private final AtlasAuthenticationFilter atlasAuthenticationFilter;
private final AtlasCSRFPreventionFilter csrfPreventionFilter;
......@@ -72,7 +69,6 @@ public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
AtlasAuthenticationProvider authenticationProvider,
AtlasAuthenticationSuccessHandler successHandler,
AtlasAuthenticationFailureHandler failureHandler,
AtlasAuthorizationFilter atlasAuthorizationFilter,
AtlasAuthenticationEntryPoint atlasAuthenticationEntryPoint,
Configuration configuration,
StaleTransactionCleanupFilter staleTransactionCleanupFilter,
......@@ -83,7 +79,6 @@ public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
this.authenticationProvider = authenticationProvider;
this.successHandler = successHandler;
this.failureHandler = failureHandler;
this.atlasAuthorizationFilter = atlasAuthorizationFilter;
this.atlasAuthenticationEntryPoint = atlasAuthenticationEntryPoint;
this.configuration = configuration;
this.staleTransactionCleanupFilter = staleTransactionCleanupFilter;
......@@ -164,7 +159,6 @@ public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
.addFilterAfter(staleTransactionCleanupFilter, BasicAuthenticationFilter.class)
.addFilterBefore(ssoAuthenticationFilter, BasicAuthenticationFilter.class)
.addFilterAfter(atlasAuthenticationFilter, SecurityContextHolderAwareRequestFilter.class)
.addFilterAfter(csrfPreventionFilter, AtlasAuthenticationFilter.class)
.addFilterAfter(atlasAuthorizationFilter, FilterSecurityInterceptor.class);
.addFilterAfter(csrfPreventionFilter, AtlasAuthenticationFilter.class);
}
}
......@@ -19,11 +19,9 @@
package org.apache.atlas.web.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
......@@ -31,88 +29,28 @@ import java.util.regex.Pattern;
*/
public final class DateTimeHelper {
public static final String ISO8601_FORMAT = "yyyy-MM-dd'T'HH:mm'Z'";
public static final String ISO8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final String DATE_PATTERN =
"(2\\d\\d\\d|19\\d\\d)-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])T" + "([0-1][0-9]|2[0-3]):([0-5][0-9])Z";
private static final Pattern PATTERN = Pattern.compile(DATE_PATTERN);
private DateTimeHelper() {
}
private static ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>() {
@Override
public DateFormat initialValue() {
DateFormat dateFormat = new SimpleDateFormat(ISO8601_FORMAT);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
}
};
public static String getTimeZoneId(TimeZone tz) {
return tz.getID();
private DateTimeHelper() {
}
public static DateFormat getDateFormat() {
DateFormat dateFormat = new SimpleDateFormat(ISO8601_FORMAT);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
return DATE_FORMAT.get();
}
public static String formatDateUTC(Date date) {
return (date != null) ? getDateFormat().format(date) : null;
}
public static Date parseDateUTC(String dateStr) {
if (!validate(dateStr)) {
throw new IllegalArgumentException(dateStr + " is not a valid UTC string");
}
try {
return getDateFormat().parse(dateStr);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public static String formatDateUTCToISO8601(final String dateString, final String dateStringFormat) {
try {
DateFormat dateFormat = new SimpleDateFormat(dateStringFormat.substring(0, dateString.length()));
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return DateTimeHelper.formatDateUTC(dateFormat.parse(dateString));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* Validate date format with regular expression.
*
* @param date date address for validation
* @return true valid date fromat, false invalid date format
*/
public static boolean validate(final String date) {
Matcher matcher = PATTERN.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int year = Integer.parseInt(matcher.group(1));
String month = matcher.group(2);
String day = matcher.group(3);
if (day.equals("31") && (month.equals("4") || month.equals("6") || month.equals("9") || month
.equals("11") || month.equals("04") || month.equals("06") || month.equals("09"))) {
return false; // only 1,3,5,7,8,10,12 has 31 days
} else if (month.equals("2") || month.equals("02")) {
// leap year
if (year % 4 == 0) {
return !(day.equals("30") || day.equals("31"));
} else {
return !(day.equals("29") || day.equals("30") || day.equals("31"));
}
} else {
return true;
}
} else {
return false;
}
} else {
return false;
}
}
}
\ No newline at end of file
......@@ -51,7 +51,6 @@
<http-basic />
<headers disabled="true"/>
<csrf disabled="true"/>
<security:custom-filter position="LAST" ref="atlasAuthorizationFilter"/>
</security:http>
<beans:bean id="krbAuthenticationFilter" class="org.apache.atlas.web.filters.AtlasAuthenticationFilter">
......@@ -102,6 +101,4 @@
<security:global-method-security
pre-post-annotations="enabled" />
<beans:bean id = "atlasAuthorizationFilter" class="org.apache.atlas.web.filters.AtlasAuthorizationFilter"/>
</beans:beans>
\ No newline at end of file
</beans:beans>
......@@ -59,24 +59,6 @@ public class AtlasAuthenticationSimpleFilterIT extends BaseSecurityTest {
}
@Test(enabled = true)
public void testSimpleLoginAndAuthorizationWithValidCrendentialsAndInvalidAccessToResource()
throws Exception {
try {
URL url = new URL("http://localhost:31000/api/atlas/admin/stack");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
String userpassword = "rangertagsync:rangertagsync"; //right password with no policy for taxonomies api
String encodedAuthorization = enc.encodeToString(userpassword.getBytes());
connection.setRequestProperty("Authorization", "Basic " +
encodedAuthorization);
connection.connect();
assertEquals(connection.getResponseCode(), 403);
} catch (Exception e) {
Assert.fail("Failed with exception " + e.getMessage());
}
}
@Test(enabled = true)
......
......@@ -51,7 +51,7 @@ public class AdminResourceTest {
when(serviceState.getState()).thenReturn(ServiceState.ServiceStateValue.ACTIVE);
AdminResource adminResource = new AdminResource(serviceState, null, null, null, null);
AdminResource adminResource = new AdminResource(serviceState, null, null, null, null, null);
Response response = adminResource.getStatus();
assertEquals(response.getStatus(), HttpServletResponse.SC_OK);
JsonNode entity = AtlasJson.parseToV1JsonNode((String) response.getEntity());
......@@ -62,7 +62,7 @@ public class AdminResourceTest {
public void testResourceGetsValueFromServiceState() throws IOException {
when(serviceState.getState()).thenReturn(ServiceState.ServiceStateValue.PASSIVE);
AdminResource adminResource = new AdminResource(serviceState, null, null, null, null);
AdminResource adminResource = new AdminResource(serviceState, null, null, null, null, null);
Response response = adminResource.getStatus();
verify(serviceState).getState();
......
......@@ -116,14 +116,17 @@ atlas.server.ha.enabled=false
#atlas.server.ids=id1
#atlas.server.address.id1=localhost:21000
#########POLICY FILE PATH #########
# atlas.auth.policy.file=policy-store.txt
######### Atlas Authorization #########
atlas.authorizer.impl=none
# atlas.authorizer.impl=simple
# atlas.authorizer.simple.authz.policy.file=atlas-simple-authz-policy.json
######### Atlas Authentication #########
atlas.authentication.method.file=true
atlas.authentication.method.ldap.type=none
# atlas.authentication.method.file.filename=users-credentials.properties
atlas.authentication.method.kerberos=false
# atlas.authentication.method.file.filename=users-credentials.properties
######### Gremlin Search Configuration #########
# Set to false to disable gremlin search.
atlas.search.gremlin.enable=true
\ No newline at end of file
atlas.search.gremlin.enable=true
......@@ -50,7 +50,6 @@
<http-basic />
<headers disabled="true"/>
<csrf disabled="true"/>
<security:custom-filter position="LAST" ref="atlasAuthorizationFilter"/>
</security:http>
<beans:bean id="userDAO" class="org.apache.atlas.web.dao.UserDao" init-method="init"/>
......@@ -113,6 +112,4 @@
</security:authentication-manager>
<security:global-method-security pre-post-annotations="enabled" />
<beans:bean id = "atlasAuthorizationFilter" class="org.apache.atlas.web.filters.AtlasAuthorizationFilter"/>
</beans:beans>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment