diff --git a/cdap-explore/src/test/java/io/cdap/cdap/explore/service/BaseHiveExploreServiceTest.java b/cdap-explore/src/test/java/io/cdap/cdap/explore/service/BaseHiveExploreServiceTest.java index 68906594a107..78b0f1b321c2 100644 --- a/cdap-explore/src/test/java/io/cdap/cdap/explore/service/BaseHiveExploreServiceTest.java +++ b/cdap-explore/src/test/java/io/cdap/cdap/explore/service/BaseHiveExploreServiceTest.java @@ -64,7 +64,7 @@ import io.cdap.cdap.security.auth.context.AuthenticationContextModules; import io.cdap.cdap.security.authorization.AuthorizationEnforcementModule; import io.cdap.cdap.security.authorization.AuthorizationTestModule; -import io.cdap.cdap.security.authorization.InMemoryAuthorizer; +import io.cdap.cdap.security.authorization.InMemoryAccessController; import io.cdap.cdap.security.impersonation.DefaultOwnerAdmin; import io.cdap.cdap.security.impersonation.OwnerAdmin; import io.cdap.cdap.security.impersonation.UGIProvider; @@ -147,7 +147,7 @@ protected static void initialize(CConfiguration cConf, TemporaryFolder tmpFolder Configuration hConf = new Configuration(); if (enableAuthorization) { LocationFactory locationFactory = new LocalLocationFactory(tmpFolder.newFolder()); - Location authExtensionJar = AppJarHelper.createDeploymentJar(locationFactory, InMemoryAuthorizer.class); + Location authExtensionJar = AppJarHelper.createDeploymentJar(locationFactory, InMemoryAccessController.class); cConf.setBoolean(Constants.Security.ENABLED, true); cConf.setBoolean(Constants.Security.Authorization.ENABLED, true); cConf.set(Constants.Security.Authorization.EXTENSION_JAR_PATH, authExtensionJar.toURI().getPath()); diff --git a/cdap-security-spi/src/test/java/io/cdap/cdap/security/spi/authorization/AuthorizerTest.java b/cdap-security-spi/src/test/java/io/cdap/cdap/security/spi/authorization/AuthorizerTest.java deleted file mode 100644 index c28f2cedeb9a..000000000000 --- a/cdap-security-spi/src/test/java/io/cdap/cdap/security/spi/authorization/AuthorizerTest.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright © 2015-2016 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package io.cdap.cdap.security.spi.authorization; - -import io.cdap.cdap.proto.id.EntityId; -import io.cdap.cdap.proto.id.NamespaceId; -import io.cdap.cdap.proto.security.Action; -import io.cdap.cdap.proto.security.Authorizable; -import io.cdap.cdap.proto.security.Principal; -import io.cdap.cdap.proto.security.Privilege; -import io.cdap.cdap.proto.security.Role; -import org.junit.Assert; -import org.junit.Test; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -/** - * Tests for {@link Authorizer}. - */ -public abstract class AuthorizerTest { - - private final NamespaceId namespace = new NamespaceId("foo"); - private final Principal user = new Principal("alice", Principal.PrincipalType.USER); - - protected abstract Authorizer get(); - - @Test - public void testSimple() throws Exception { - Authorizer authorizer = get(); - - verifyAuthFailure(namespace, user, Action.READ); - - authorizer.grant(Authorizable.fromEntityId(namespace), user, Collections.singleton(Action.READ)); - authorizer.enforce(namespace, user, Action.READ); - - Set expectedPrivileges = new HashSet<>(); - expectedPrivileges.add(new Privilege(namespace, Action.READ)); - Assert.assertEquals(expectedPrivileges, authorizer.listPrivileges(user)); - - authorizer.revoke(Authorizable.fromEntityId(namespace), user, Collections.singleton(Action.READ)); - verifyAuthFailure(namespace, user, Action.READ); - } - - @Test - public void testWildcard() throws Exception { - Authorizer authorizer = get(); - - verifyAuthFailure(namespace, user, Action.READ); - - authorizer.grant(Authorizable.fromEntityId(namespace), user, EnumSet.allOf(Action.class)); - authorizer.enforce(namespace, user, Action.READ); - authorizer.enforce(namespace, user, Action.WRITE); - authorizer.enforce(namespace, user, Action.ADMIN); - authorizer.enforce(namespace, user, Action.EXECUTE); - - authorizer.revoke(Authorizable.fromEntityId(namespace), user, EnumSet.allOf(Action.class)); - verifyAuthFailure(namespace, user, Action.READ); - } - - @Test - public void testAll() throws Exception { - Authorizer authorizer = get(); - - verifyAuthFailure(namespace, user, Action.READ); - - authorizer.grant(Authorizable.fromEntityId(namespace), user, EnumSet.allOf(Action.class)); - authorizer.enforce(namespace, user, Action.READ); - authorizer.enforce(namespace, user, Action.WRITE); - authorizer.enforce(namespace, user, Action.ADMIN); - authorizer.enforce(namespace, user, Action.EXECUTE); - - authorizer.revoke(Authorizable.fromEntityId(namespace), user, EnumSet.allOf(Action.class)); - verifyAuthFailure(namespace, user, Action.READ); - - Principal role = new Principal("admins", Principal.PrincipalType.ROLE); - authorizer.grant(Authorizable.fromEntityId(namespace), user, Collections.singleton(Action.READ)); - authorizer.grant(Authorizable.fromEntityId(namespace), role, EnumSet.allOf(Action.class)); - authorizer.revoke(Authorizable.fromEntityId(namespace)); - verifyAuthFailure(namespace, user, Action.READ); - verifyAuthFailure(namespace, role, Action.ADMIN); - verifyAuthFailure(namespace, role, Action.READ); - verifyAuthFailure(namespace, role, Action.WRITE); - verifyAuthFailure(namespace, role, Action.EXECUTE); - } - - @Test - public void testRBAC() throws Exception { - Authorizer authorizer = get(); - - Role admins = new Role("admins"); - Role engineers = new Role("engineers"); - // create a role - authorizer.createRole(admins); - // add another role - authorizer.createRole(engineers); - - // listing role should show the added role - Set roles = authorizer.listAllRoles(); - Set expectedRoles = new HashSet<>(); - expectedRoles.add(admins); - expectedRoles.add(engineers); - Assert.assertEquals(expectedRoles, roles); - - // creating a role which already exists should throw an exception - try { - authorizer.createRole(admins); - Assert.fail(String.format("Created a role %s which already exists. Should have failed.", admins.getName())); - } catch (AlreadyExistsException expected) { - // expected - } - - // drop an existing role - authorizer.dropRole(admins); - - // the list should not have the dropped role - roles = authorizer.listAllRoles(); - Assert.assertEquals(Collections.singleton(engineers), roles); - - // dropping a non-existing role should throw exception - try { - authorizer.dropRole(admins); - Assert.fail(String.format("Dropped a role %s which does not exists. Should have failed.", admins.getName())); - } catch (NotFoundException expected) { - // expected - } - - // add an user to an existing role - Principal spiderman = new Principal("spiderman", Principal.PrincipalType.USER); - authorizer.addRoleToPrincipal(engineers, spiderman); - - // add an user to an non-existing role should throw an exception - try { - authorizer.addRoleToPrincipal(admins, spiderman); - Assert.fail(String.format("Added role %s to principal %s. Should have failed.", admins, spiderman)); - } catch (NotFoundException expected) { - // expectedRoles - } - - // check listing roles for spiderman have engineers role - Assert.assertEquals(Collections.singleton(engineers), authorizer.listRoles(spiderman)); - - // authorization checks with roles - NamespaceId ns1 = new NamespaceId("ns1"); - - // check that spiderman who has engineers roles cannot read from ns1 - verifyAuthFailure(ns1, spiderman, Action.READ); - - // give a permission to engineers role - authorizer.grant(Authorizable.fromEntityId(ns1), engineers, Collections.singleton(Action.READ)); - - // check that a spiderman who has engineers role has access - authorizer.enforce(ns1, spiderman, Action.READ); - - // list privileges for spiderman should have read action on ns1 - Assert.assertEquals(Collections.singleton(new Privilege(ns1, Action.READ)), - authorizer.listPrivileges(spiderman)); - - // revoke action from the role - authorizer.revoke(Authorizable.fromEntityId(ns1), engineers, Collections.singleton(Action.READ)); - - // now the privileges for spiderman should be empty - Assert.assertEquals(Collections.EMPTY_SET, authorizer.listPrivileges(spiderman)); - - // check that the user of this role is not authorized to do the revoked operation - verifyAuthFailure(ns1, spiderman, Action.READ); - - // remove an user from a existing role - authorizer.removeRoleFromPrincipal(engineers, spiderman); - - // check listing roles for spiderman should be empty - Assert.assertEquals(Collections.EMPTY_SET, authorizer.listRoles(spiderman)); - - // remove an user from a non-existing role should throw exception - try { - authorizer.removeRoleFromPrincipal(admins, spiderman); - Assert.fail(String.format("Removed non-existing role %s from principal %s. Should have failed.", admins, - spiderman)); - } catch (NotFoundException expected) { - // expectedRoles - } - } - - private void verifyAuthFailure(EntityId entity, Principal principal, Action action) throws Exception { - try { - get().enforce(entity, principal, action); - Assert.fail(String.format("Expected authorization failure, but it succeeded for entity %s, principal %s," + - " action %s", entity, principal, action)); - } catch (UnauthorizedException expected) { - // expected - } - } -} diff --git a/cdap-security/src/main/java/io/cdap/cdap/proto/security/AuthorizationPrivilege.java b/cdap-security/src/main/java/io/cdap/cdap/proto/security/AuthorizationPrivilege.java index 20c752c957ba..4fa247dab442 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/proto/security/AuthorizationPrivilege.java +++ b/cdap-security/src/main/java/io/cdap/cdap/proto/security/AuthorizationPrivilege.java @@ -33,8 +33,6 @@ */ public class AuthorizationPrivilege { private final EntityId entityId; - //Will only be set from GSON. Also will automatically be converted to permissions by PermissionAdapterFactory - private final Set actions; private final Set permissions; private final Principal principal; private final EntityType childEntityType; @@ -44,7 +42,6 @@ public AuthorizationPrivilege(Principal principal, EntityId entityId, Set getPermissions() { return permissions; } - - @Nullable - public Set getActions() { - return actions; - } - /** * @return child entity type for {@link AccessEnforcer#enforceOnParent(EntityType, EntityId, Principal, Permission)} * checks. @@ -85,7 +76,7 @@ public boolean equals(Object o) { AuthorizationPrivilege that = (AuthorizationPrivilege) o; return Objects.equals(entityId, that.entityId) && permissions.equals(that.permissions) && Objects.equals(childEntityType, that.childEntityType) && - Objects.equals(actions, that.actions) && Objects.equals(principal, that.principal); + Objects.equals(principal, that.principal); } @Override @@ -97,7 +88,6 @@ public int hashCode() { public String toString() { return "AuthorizationPrivilege {" + "entityId=" + entityId + - ", actions=" + actions + ", permissions=" + permissions + ", principal=" + principal + ", childEntityType=" + childEntityType + diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AbstractAccessEnforcer.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AbstractAccessEnforcer.java index 11ab0aa23b4d..0aa8d8d8c6e4 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AbstractAccessEnforcer.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AbstractAccessEnforcer.java @@ -38,28 +38,6 @@ public abstract class AbstractAccessEnforcer implements AccessEnforcer { this.securityAuthorizationEnabled = AuthorizationUtil.isSecurityAuthorizationEnabled(cConf); } - @Override - public void enforce(EntityId entity, Principal principal, Set permissions) - throws AccessException { - if (!isSecurityAuthorizationEnabled()) { - return; - } - - Set disallowed = new HashSet<>(); - UnauthorizedException unauthorizedException = new UnauthorizedException(principal, entity); - for (Permission permission : permissions) { - try { - enforce(entity, principal, permission); - } catch (UnauthorizedException e) { - disallowed.add(permission); - unauthorizedException.addSuppressed(e); - } - } - if (!disallowed.isEmpty()) { - throw new UnauthorizedException(principal, disallowed, entity, unauthorizedException); - } - } - protected boolean isSecurityAuthorizationEnabled() { return securityAuthorizationEnabled; } diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java deleted file mode 100644 index 273a34b51fe8..000000000000 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright © 2021 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import io.cdap.cdap.api.security.AccessException; -import io.cdap.cdap.proto.id.EntityId; -import io.cdap.cdap.proto.security.Action; -import io.cdap.cdap.proto.security.Authorizable; -import io.cdap.cdap.proto.security.Principal; -import io.cdap.cdap.proto.security.Privilege; -import io.cdap.cdap.proto.security.Role; -import io.cdap.cdap.proto.security.StandardPermission; -import io.cdap.cdap.security.spi.authorization.AccessController; -import io.cdap.cdap.security.spi.authorization.AuthorizationContext; -import io.cdap.cdap.security.spi.authorization.Authorizer; - -import java.util.Set; -import java.util.stream.Collectors; -import javax.inject.Inject; - -/** - * Wraps an {@link AccessController} and makes {@link Authorizer} - * out of it. - * TODO: remove after platform fully migrated to use AccessController directly - */ -public class AccessControllerWrapper extends AccessEnforcerWrapper implements Authorizer { - private final AccessController accessController; - - @Inject - public AccessControllerWrapper(AccessController accessController) { - super(accessController); - this.accessController = accessController; - } - - @Override - public void createRole(Role role) throws AccessException { - accessController.createRole(role); - } - - @Override - public void dropRole(Role role) throws AccessException { - accessController.dropRole(role); - } - - @Override - public void addRoleToPrincipal(Role role, Principal principal) throws AccessException { - accessController.addRoleToPrincipal(role, principal); - } - - @Override - public void removeRoleFromPrincipal(Role role, Principal principal) throws AccessException { - accessController.removeRoleFromPrincipal(role, principal); - } - - @Override - public Set listRoles(Principal principal) throws AccessException { - return accessController.listRoles(principal); - } - - @Override - public Set listAllRoles() throws AccessException { - return accessController.listAllRoles(); - } - - @Override - public void revoke(Authorizable authorizable) throws AccessException { - accessController.revoke(authorizable); - } - - @Override - public void isVisible(EntityId entityId, Principal principal) throws AccessException { - accessController.enforce(entityId, principal, StandardPermission.GET); - } - - @Override - public Set isVisible(Set entityIds, Principal principal) - throws AccessException { - return accessController.isVisible(entityIds, principal); - } - - @Override - public Set listPrivileges(Principal principal) throws Exception { - return accessController.listGrants(principal).stream() - .map(p -> new Privilege(p.getAuthorizable(), - AuthorizerWrapper.getAction(p.getPermission(), p.getAuthorizable().getEntityType()))) - .collect(Collectors.toSet()); - } - - @Override - public void grant(Authorizable authorizable, Principal principal, Set actions) throws Exception { - accessController.grant(authorizable, principal, getPermissions(actions)); - } - - @Override - public void revoke(Authorizable authorizable, Principal principal, Set actions) throws Exception { - accessController.revoke(authorizable, principal, getPermissions(actions)); - } - - @Override - public void initialize(AuthorizationContext context) throws Exception { - - } - - @Override - public void destroy() throws Exception { - - } -} diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessEnforcerWrapper.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessEnforcerWrapper.java deleted file mode 100644 index 927e67fe8713..000000000000 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessEnforcerWrapper.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright © 2021 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import io.cdap.cdap.api.security.AccessException; -import io.cdap.cdap.proto.id.EntityId; -import io.cdap.cdap.proto.security.Action; -import io.cdap.cdap.proto.security.Permission; -import io.cdap.cdap.proto.security.Principal; -import io.cdap.cdap.proto.security.StandardPermission; -import io.cdap.cdap.security.spi.authorization.AccessEnforcer; -import io.cdap.cdap.security.spi.authorization.AuthorizationEnforcer; - -import java.util.Set; -import java.util.stream.Collectors; -import javax.inject.Inject; - -/** - * Wraps an {@link io.cdap.cdap.security.spi.authorization.AccessEnforcer} and makes {@link AuthorizationEnforcer} - * out of it. - * TODO: remove after platform fully migrated to use AccessController directly - */ -public class AccessEnforcerWrapper implements AuthorizationEnforcer { - private final AccessEnforcer accessEnforcer; - - @Inject - public AccessEnforcerWrapper(AccessEnforcer accessEnforcer) { - this.accessEnforcer = accessEnforcer; - } - - @Override - public void enforce(EntityId entity, Principal principal, Action action) throws AccessException { - accessEnforcer.enforce(entity, principal, action.getPermission()); - } - - @Override - public void enforce(EntityId entity, Principal principal, Set actions) throws Exception { - accessEnforcer.enforce(entity, principal, getPermissions(actions)); - } - - - @Override - public void isVisible(EntityId entityId, Principal principal) throws AccessException { - accessEnforcer.enforce(entityId, principal, StandardPermission.GET); - } - - @Override - public Set isVisible(Set entityIds, Principal principal) - throws AccessException { - return accessEnforcer.isVisible(entityIds, principal); - } - - protected Set getPermissions(Set actions) { - return actions.stream().map(Action::getPermission).collect(Collectors.toSet()); - } - -} diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizationEnforcementModule.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizationEnforcementModule.java index 740ff4259ac8..16f6b5a391cd 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizationEnforcementModule.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizationEnforcementModule.java @@ -21,11 +21,10 @@ import com.google.inject.Scopes; import io.cdap.cdap.common.runtime.RuntimeModule; import io.cdap.cdap.security.spi.authorization.AccessEnforcer; -import io.cdap.cdap.security.spi.authorization.AuthorizationEnforcer; import io.cdap.cdap.security.spi.authorization.ContextAccessEnforcer; /** - * A module that contains bindings for {@link AuthorizationEnforcer}. + * A module that contains bindings for {@link AccessEnforcer}. */ public class AuthorizationEnforcementModule extends RuntimeModule { @@ -35,7 +34,6 @@ public Module getInMemoryModules() { @Override protected void configure() { bind(AccessEnforcer.class).to(DefaultAccessEnforcer.class).in(Scopes.SINGLETON); - bind(AuthorizationEnforcer.class).to(AccessEnforcerWrapper.class).in(Scopes.SINGLETON); bind(ContextAccessEnforcer.class).to(DefaultContextAccessEnforcer.class).in(Scopes.SINGLETON); } }; @@ -47,7 +45,6 @@ public Module getStandaloneModules() { @Override protected void configure() { bind(AccessEnforcer.class).to(DefaultAccessEnforcer.class).in(Scopes.SINGLETON); - bind(AuthorizationEnforcer.class).to(AccessEnforcerWrapper.class).in(Scopes.SINGLETON); bind(ContextAccessEnforcer.class).to(DefaultContextAccessEnforcer.class).in(Scopes.SINGLETON); } }; @@ -63,7 +60,6 @@ public Module getDistributedModules() { @Override protected void configure() { bind(AccessEnforcer.class).to(RemoteAccessEnforcer.class).in(Scopes.SINGLETON); - bind(AuthorizationEnforcer.class).to(AccessEnforcerWrapper.class).in(Scopes.SINGLETON); bind(ContextAccessEnforcer.class).to(DefaultContextAccessEnforcer.class).in(Scopes.SINGLETON); } }; @@ -77,7 +73,6 @@ public AbstractModule getMasterModule() { @Override protected void configure() { bind(AccessEnforcer.class).to(DefaultAccessEnforcer.class).in(Scopes.SINGLETON); - bind(AuthorizationEnforcer.class).to(AccessEnforcerWrapper.class).in(Scopes.SINGLETON); bind(ContextAccessEnforcer.class).to(DefaultContextAccessEnforcer.class).in(Scopes.SINGLETON); } }; diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizerInstantiator.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizerInstantiator.java deleted file mode 100644 index ca1b35d6f366..000000000000 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AuthorizerInstantiator.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright © 2016-2021 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import com.google.common.annotations.VisibleForTesting; -import io.cdap.cdap.common.conf.CConfiguration; -import io.cdap.cdap.security.spi.authorization.Authorizer; - -import java.util.function.Supplier; -import javax.inject.Inject; - -/** - * Temporary gateway for old platform classes to get {@link Authorizer} until after migration - * to {@link io.cdap.cdap.security.spi.authorization.AccessController} is finished. - */ -public class AuthorizerInstantiator implements Supplier { - private final AccessControllerInstantiator accessControllerInstantiator; - - @Inject - public AuthorizerInstantiator(AccessControllerInstantiator accessControllerInstantiator) { - this.accessControllerInstantiator = accessControllerInstantiator; - } - - @VisibleForTesting - public AuthorizerInstantiator(CConfiguration cConf, AuthorizationContextFactory authorizationContextFactory) { - this(new AccessControllerInstantiator(cConf, authorizationContextFactory)); - } - - @Override - public Authorizer get() { - return new AccessControllerWrapper(accessControllerInstantiator.get()); - } -} diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DefaultAccessEnforcer.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DefaultAccessEnforcer.java index 0a7aa6e7bfd7..a191b496511c 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DefaultAccessEnforcer.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DefaultAccessEnforcer.java @@ -31,7 +31,6 @@ import io.cdap.cdap.proto.security.Principal; import io.cdap.cdap.security.auth.CipherException; import io.cdap.cdap.security.auth.TinkCipher; -import io.cdap.cdap.security.spi.authorization.AuthorizationEnforcer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,8 +42,8 @@ import javax.annotation.Nullable; /** - * An implementation of {@link AuthorizationEnforcer} that runs on the master. It calls the authorizer directly to - * enforce authorization policies. + * An implementation of {@link io.cdap.cdap.security.spi.authorization.AccessEnforcer} that runs on the master. + * It calls the access controller directly to enforce authorization policies. */ @Singleton public class DefaultAccessEnforcer extends AbstractAccessEnforcer { @@ -68,14 +67,6 @@ public class DefaultAccessEnforcer extends AbstractAccessEnforcer { this.logTimeTakenAsWarn = cConf.getInt(Constants.Security.Authorization.EXTENSION_OPERATION_TIME_WARN_THRESHOLD); } - @Override - public void enforce(EntityId entity, Principal principal, Permission permission) throws AccessException { - if (!isSecurityAuthorizationEnabled()) { - return; - } - doEnforce(entity, principal, Collections.singleton(permission)); - } - @Override public void enforce(EntityId entity, Principal principal, Set permissions) throws AccessException { diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DelegatingPrivilegeManager.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DelegatingPrivilegeManager.java deleted file mode 100644 index b2e5bfc3c1c8..000000000000 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/DelegatingPrivilegeManager.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright © 2017-2021 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import com.google.inject.Inject; -import io.cdap.cdap.proto.security.Action; -import io.cdap.cdap.proto.security.Authorizable; -import io.cdap.cdap.proto.security.Principal; -import io.cdap.cdap.proto.security.Privilege; -import io.cdap.cdap.security.spi.authorization.Authorizer; -import io.cdap.cdap.security.spi.authorization.PrivilegesManager; - -import java.util.Set; - -/** - * A {@link PrivilegesManager} implements that delegates to the authorizer. - * Having this makes Guice injection for Privilege manager simple. That reason will go away once - * https://issues.cask.co/browse/CDAP-11561 is fixed. - */ -public class DelegatingPrivilegeManager implements PrivilegesManager { - - private final Authorizer delegateAuthorizer; - - @Inject - DelegatingPrivilegeManager(AuthorizerInstantiator authorizerInstantiator) { - this.delegateAuthorizer = authorizerInstantiator.get(); - } - - @Override - public void grant(Authorizable authorizable, Principal principal, Set actions) throws Exception { - delegateAuthorizer.grant(authorizable, principal, actions); - } - - @Override - public void revoke(Authorizable authorizable, Principal principal, Set actions) throws Exception { - delegateAuthorizer.revoke(authorizable, principal, actions); - } - - @Override - public void revoke(Authorizable authorizable) throws Exception { - delegateAuthorizer.revoke(authorizable); - } - - @Override - public Set listPrivileges(Principal principal) throws Exception { - return delegateAuthorizer.listPrivileges(principal); - } -} diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAccessEnforcer.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAccessEnforcer.java index 1ae0b0f72754..d0f048077aba 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAccessEnforcer.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAccessEnforcer.java @@ -298,17 +298,6 @@ public VisibilityKey apply(EntityId entityId) { }); } - private AccessException propagateAccessException(Throwable e) throws AccessException { - if (e.getCause() != null && e instanceof ExecutionException) { - propagateAccessException(e.getCause()); - } - Throwables.propagateIfPossible(e, AccessException.class); - if (e instanceof IOException) { - return new AccessIOException(e); - } - return new AccessException(e); - } - private static class VisibilityKey { private final Principal principal; private final EntityId entityId; diff --git a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerClassLoaderTest.java b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerClassLoaderTest.java index fc656257ce9e..09c10f9c498d 100644 --- a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerClassLoaderTest.java +++ b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerClassLoaderTest.java @@ -21,6 +21,7 @@ import io.cdap.cdap.api.app.Application; import io.cdap.cdap.common.lang.ClassPathResources; import io.cdap.cdap.proto.security.Principal; +import io.cdap.cdap.security.spi.authorization.AccessController; import io.cdap.cdap.security.spi.authorization.Authorizer; import io.cdap.cdap.security.spi.authorization.UnauthorizedException; import org.apache.hadoop.conf.Configuration; @@ -58,6 +59,7 @@ public void testAuthorizerClassLoaderParentAvailableClasses() throws ClassNotFou parent.loadClass(Principal.class.getName()); // classes from cdap-security-spi should be available parent.loadClass(Authorizer.class.getName()); + parent.loadClass(AccessController.class.getName()); parent.loadClass(UnauthorizedException.class.getName()); // classes from hadoop should be available parent.loadClass(Configuration.class.getName()); diff --git a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizer.java b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizer.java deleted file mode 100644 index bc568b38e827..000000000000 --- a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizer.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright © 2016 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import com.google.common.base.Splitter; -import com.google.common.collect.Sets; -import io.cdap.cdap.proto.element.EntityType; -import io.cdap.cdap.proto.id.ApplicationId; -import io.cdap.cdap.proto.id.ArtifactId; -import io.cdap.cdap.proto.id.EntityId; -import io.cdap.cdap.proto.id.ProgramId; -import io.cdap.cdap.proto.security.Action; -import io.cdap.cdap.proto.security.Authorizable; -import io.cdap.cdap.proto.security.Principal; -import io.cdap.cdap.proto.security.Privilege; -import io.cdap.cdap.proto.security.Role; -import io.cdap.cdap.security.spi.authorization.AbstractAuthorizer; -import io.cdap.cdap.security.spi.authorization.AlreadyExistsException; -import io.cdap.cdap.security.spi.authorization.AuthorizationContext; -import io.cdap.cdap.security.spi.authorization.Authorizer; -import io.cdap.cdap.security.spi.authorization.NotFoundException; -import io.cdap.cdap.security.spi.authorization.UnauthorizedException; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * In-memory implementation of {@link Authorizer}. - */ -public class InMemoryAuthorizer extends AbstractAuthorizer { - - private final ConcurrentMap>> privileges = - new ConcurrentHashMap<>(); - private final ConcurrentMap> roleToPrincipals = new ConcurrentHashMap<>(); - private final Set superUsers = new HashSet<>(); - // Bypass enforcement for tests that want to simulate every user as a super user - private final Principal allSuperUsers = new Principal("*", Principal.PrincipalType.USER); - - @Override - public void initialize(AuthorizationContext context) throws Exception { - Properties properties = context.getExtensionProperties(); - if (properties.containsKey("superusers")) { - for (String superuser : Splitter.on(",").trimResults().omitEmptyStrings() - .split(properties.getProperty("superusers"))) { - superUsers.add(new Principal(superuser, Principal.PrincipalType.USER)); - } - } - } - - @Override - public void enforce(EntityId entity, Principal principal, Set actions) throws UnauthorizedException { - // super users do not have any enforcement - if (superUsers.contains(principal) || superUsers.contains(allSuperUsers)) { - return; - } - // actions allowed for this principal - Set allowed = getActions(entity, principal); - if (allowed.containsAll(actions)) { - return; - } - Set allowedForRoles = new HashSet<>(); - // actions allowed for any of the roles to which this principal belongs if its not a role - if (principal.getType() != Principal.PrincipalType.ROLE) { - for (Role role : getRoles(principal)) { - allowedForRoles.addAll(getActions(entity, role)); - } - } - if (!allowedForRoles.containsAll(actions)) { - throw new UnauthorizedException(principal, Sets.difference(actions, allowed), entity); - } - } - - @Override - public Set isVisible(Set entityIds, Principal principal) throws Exception { - if (superUsers.contains(principal) || superUsers.contains(allSuperUsers)) { - return entityIds; - } - Set results = new HashSet<>(); - for (EntityId entityId : entityIds) { - for (Authorizable existingEntity : privileges.keySet()) { - if (isParent(entityId, existingEntity.getEntityParts())) { - Set allowedActions = privileges.get(existingEntity).get(principal); - if (allowedActions != null && !allowedActions.isEmpty()) { - results.add(entityId); - break; - } - } - } - } - return results; - } - - @Override - public void grant(Authorizable authorizable, Principal principal, Set actions) throws Exception { - getActions(authorizable, principal).addAll(actions); - } - - @Override - public void revoke(Authorizable authorizable, Principal principal, Set actions) throws Exception { - getActions(authorizable, principal).removeAll(actions); - } - - @Override - public void revoke(Authorizable authorizable) throws Exception { - privileges.remove(authorizable); - } - - @Override - public void createRole(Role role) throws AlreadyExistsException { - if (roleToPrincipals.containsKey(role)) { - throw new AlreadyExistsException(role); - } - // NOTE: A concurrent put might happen, hence it should still result as RoleAlreadyExistsException. - Set principals = Collections.newSetFromMap(new ConcurrentHashMap()); - if (roleToPrincipals.putIfAbsent(role, principals) != null) { - throw new AlreadyExistsException(role); - } - } - - @Override - public void dropRole(Role role) throws NotFoundException { - Set removed = roleToPrincipals.remove(role); - if (removed == null) { - throw new NotFoundException(role); - } - } - - @Override - public void addRoleToPrincipal(Role role, Principal principal) throws NotFoundException { - Set principals = roleToPrincipals.get(role); - if (principals == null) { - throw new NotFoundException(role); - } - principals.add(principal); - } - - @Override - public void removeRoleFromPrincipal(Role role, Principal principal) throws NotFoundException { - Set principals = roleToPrincipals.get(role); - if (principals == null) { - throw new NotFoundException(role); - } - principals.remove(principal); - } - - @Override - public Set listRoles(Principal principal) { - return Collections.unmodifiableSet(getRoles(principal)); - } - - @Override - public Set listAllRoles() { - return Collections.unmodifiableSet(roleToPrincipals.keySet()); - } - - @Override - public Set listPrivileges(Principal principal) { - Set privileges = new HashSet<>(); - // privileges for this principal - privileges.addAll(getPrivileges(principal)); - - // privileges for the role to which this principal belongs to if its not a role - if (principal.getType() != Principal.PrincipalType.ROLE) { - for (Role role : roleToPrincipals.keySet()) { - privileges.addAll(getPrivileges(role)); - } - } - return Collections.unmodifiableSet(privileges); - } - - private Set getPrivileges(Principal principal) { - Set result = new HashSet<>(); - for (Map.Entry>> entry : privileges.entrySet()) { - Authorizable authorizable = entry.getKey(); - Set actions = getActions(authorizable, principal); - for (Action action : actions) { - result.add(new Privilege(authorizable, action)); - } - } - return Collections.unmodifiableSet(result); - } - - private Set getActions(EntityId entityId, Principal principal) { - return getActions(Authorizable.fromEntityId(entityId), principal); - } - - private Set getActions(Authorizable authorizable, Principal principal) { - ConcurrentMap> allActions = privileges.get(authorizable); - if (allActions == null) { - allActions = new ConcurrentHashMap<>(); - ConcurrentMap> existingAllActions = privileges.putIfAbsent(authorizable, allActions); - allActions = (existingAllActions == null) ? allActions : existingAllActions; - } - Set actions = allActions.get(principal); - if (actions != null) { - return actions; - } - - actions = Collections.newSetFromMap(new ConcurrentHashMap()); - Set existingActions = allActions.putIfAbsent(principal, actions); - return existingActions == null ? actions : existingActions; - } - - private Set getRoles(Principal principal) { - Set roles = new HashSet<>(); - for (Map.Entry> roleSetEntry : roleToPrincipals.entrySet()) { - if (roleSetEntry.getValue().contains(principal)) { - roles.add(roleSetEntry.getKey()); - } - } - return roles; - } - - private boolean isParent(EntityId guessingParent, Map guessingChild) { - Map questionedEntityParts = Authorizable.fromEntityId(guessingParent).getEntityParts(); - for (EntityType entityType : questionedEntityParts.keySet()) { - if (!(guessingChild.containsKey(entityType) && - guessingChild.get(entityType).equals(questionedEntityParts.get(entityType)))) { - return false; - } - } - return true; - } - - public final class AuthorizableEntityId { - private final EntityId entityId; - - AuthorizableEntityId(EntityId entityId) { - this.entityId = entityId; - } - - public EntityId getEntityId() { - return entityId; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - AuthorizableEntityId that = (AuthorizableEntityId) o; - if (!that.getEntityId().getEntityType().equals(entityId.getEntityType())) { - return false; - } - - EntityId thatEntityId = that.getEntityId(); - if (entityId.getEntityType().equals(EntityType.ARTIFACT)) { - ArtifactId artifactId = (ArtifactId) entityId; - ArtifactId thatArtifactId = (ArtifactId) thatEntityId; - return Objects.equals(artifactId.getNamespace(), thatArtifactId.getNamespace()) && - Objects.equals(artifactId.getArtifact(), thatArtifactId.getArtifact()); - } - if (entityId.getEntityType().equals(EntityType.APPLICATION)) { - ApplicationId applicationId = (ApplicationId) entityId; - ApplicationId thatApplicationId = (ApplicationId) thatEntityId; - return Objects.equals(applicationId.getNamespace(), thatApplicationId.getNamespace()) && - Objects.equals(applicationId.getApplication(), thatApplicationId.getApplication()); - } - if (entityId.getEntityType().equals(EntityType.PROGRAM)) { - ProgramId programId = (ProgramId) entityId; - ProgramId thatProgramId = (ProgramId) thatEntityId; - return Objects.equals(programId.getNamespace(), thatProgramId.getNamespace()) && - Objects.equals(programId.getApplication(), thatProgramId.getApplication()) && - Objects.equals(programId.getType(), thatProgramId.getType()) && - Objects.equals(programId.getProgram(), thatProgramId.getProgram()); - } - return Objects.equals(entityId, that.entityId); - } - - @Override - public int hashCode() { - if (entityId.getEntityType().equals(EntityType.ARTIFACT)) { - ArtifactId artifactId = (ArtifactId) entityId; - return Objects.hash(artifactId.getEntityType(), artifactId.getNamespace(), artifactId.getArtifact()); - } - if (entityId.getEntityType().equals(EntityType.APPLICATION)) { - ApplicationId applicationId = (ApplicationId) entityId; - return Objects.hash(applicationId.getEntityType(), applicationId.getNamespace(), - applicationId.getApplication()); - } - if (entityId.getEntityType().equals(EntityType.PROGRAM)) { - ProgramId programId = (ProgramId) entityId; - return Objects.hash(programId.getEntityType(), programId.getNamespace(), programId.getApplication(), - programId.getType(), programId.getProgram()); - } - return Objects.hash(entityId); - } - } -} diff --git a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizerTest.java b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizerTest.java deleted file mode 100644 index a4e4d99bbc0a..000000000000 --- a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAuthorizerTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2016 Cask Data, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package io.cdap.cdap.security.authorization; - -import io.cdap.cdap.security.spi.authorization.Authorizer; -import io.cdap.cdap.security.spi.authorization.AuthorizerTest; - -/** - * Tests for {@link InMemoryAuthorizer}. - */ -public class InMemoryAuthorizerTest extends AuthorizerTest { - @Override - protected Authorizer get() { - return new InMemoryAuthorizer(); - } -} diff --git a/cdap-unit-test/src/main/java/io/cdap/cdap/test/TestBase.java b/cdap-unit-test/src/main/java/io/cdap/cdap/test/TestBase.java index d2f1092b8a49..03fce610820f 100644 --- a/cdap-unit-test/src/main/java/io/cdap/cdap/test/TestBase.java +++ b/cdap-unit-test/src/main/java/io/cdap/cdap/test/TestBase.java @@ -125,13 +125,11 @@ import io.cdap.cdap.scheduler.CoreSchedulerService; import io.cdap.cdap.scheduler.Scheduler; import io.cdap.cdap.security.authorization.AccessControllerInstantiator; -import io.cdap.cdap.security.authorization.AccessControllerWrapper; import io.cdap.cdap.security.authorization.AuthorizationEnforcementModule; import io.cdap.cdap.security.authorization.InvalidAccessControllerException; import io.cdap.cdap.security.guice.SecureStoreServerModule; import io.cdap.cdap.security.spi.authentication.SecurityRequestContext; import io.cdap.cdap.security.spi.authorization.AccessController; -import io.cdap.cdap.security.spi.authorization.Authorizer; import io.cdap.cdap.spi.data.StructuredTableAdmin; import io.cdap.cdap.spi.data.table.StructuredTableRegistry; import io.cdap.cdap.spi.metadata.MetadataStorage; @@ -1066,11 +1064,6 @@ protected static AccessController getAccessController() throws IOException, Inva return accessControllerInstantiator.get(); } - @Beta - protected static Authorizer getAuthorizer() { - return new AccessControllerWrapper(accessControllerInstantiator.get()); - } - /** * Returns a {@link PreviewManager} to interact with preview. */