This is an automated email from the ASF dual-hosted git repository. jshao pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit 7b329713decfadaf5cb65050a76481f60dbf0dae Author: yangyang zhong <[email protected]> AuthorDate: Wed May 14 17:22:46 2025 +0800 [#6829] feat(authz): Introduce AuthorizationExpressionEvaluator and Converter (#7077) ### What changes were proposed in this pull request? Introduce AuthorizationExpressionEvaluator and AuthorizationConverter for expression conversion and execution of authorization checks. ### Why are the changes needed? Fix: #6829 ### Does this PR introduce _any_ user-facing change? None ### How was this patch tested? org.apache.gravitino.server.authorization.expression.TestAuthorizationConverter org.apache.gravitino.server.authorization.expression.TestAuthorizationExpressionEvaluator --- .../org/apache/gravitino/auth/AuthConstants.java | 3 + server-common/build.gradle.kts | 1 + .../server/authorization/GravitinoAuthorizer.java | 10 ++ .../authorization/PassThroughAuthorizer.java | 5 + .../expression/AuthorizationConverter.java | 41 ------ .../AuthorizationExpressionConverter.java | 81 +++++++++++ .../AuthorizationExpressionEvaluator.java | 63 ++++++++- .../TestAuthorizationExpressionConverter.java | 80 +++++++++++ .../TestAuthorizationExpressionEvaluator.java | 149 +++++++++++++++++++++ 9 files changed, 385 insertions(+), 48 deletions(-) diff --git a/common/src/main/java/org/apache/gravitino/auth/AuthConstants.java b/common/src/main/java/org/apache/gravitino/auth/AuthConstants.java index a54847b016..38ce4ac2b0 100644 --- a/common/src/main/java/org/apache/gravitino/auth/AuthConstants.java +++ b/common/src/main/java/org/apache/gravitino/auth/AuthConstants.java @@ -44,6 +44,9 @@ public final class AuthConstants { /** The default username used for anonymous access. */ public static final String ANONYMOUS_USER = "anonymous"; + /** OWNER. */ + public static final String OWNER = "OWNER"; + /** * The default name of the attribute that stores the authenticated principal in the request. * diff --git a/server-common/build.gradle.kts b/server-common/build.gradle.kts index 3341b4f5fa..f8d27a0446 100644 --- a/server-common/build.gradle.kts +++ b/server-common/build.gradle.kts @@ -44,6 +44,7 @@ dependencies { implementation(libs.jackson.datatype.jsr310) implementation(libs.jackson.databind) implementation(libs.prometheus.servlet) + implementation(libs.ognl) testImplementation(libs.commons.io) testImplementation(libs.junit.jupiter.api) diff --git a/server-common/src/main/java/org/apache/gravitino/server/authorization/GravitinoAuthorizer.java b/server-common/src/main/java/org/apache/gravitino/server/authorization/GravitinoAuthorizer.java index fdadac206a..710fe93601 100644 --- a/server-common/src/main/java/org/apache/gravitino/server/authorization/GravitinoAuthorizer.java +++ b/server-common/src/main/java/org/apache/gravitino/server/authorization/GravitinoAuthorizer.java @@ -45,4 +45,14 @@ public interface GravitinoAuthorizer extends Closeable { String metalake, MetadataObject metadataObject, Privilege.Name privilege); + + /** + * Determine whether the user is the Owner of a certain metadata object. + * + * @param principal the user principal + * @param metalake the metalake + * @param metadataObject the metadataObject. + * @return authorization result. + */ + boolean isOwner(Principal principal, String metalake, MetadataObject metadataObject); } diff --git a/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java b/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java index 645b946b6b..fa655617dc 100644 --- a/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java +++ b/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java @@ -40,6 +40,11 @@ public class PassThroughAuthorizer implements GravitinoAuthorizer { return true; } + @Override + public boolean isOwner(Principal principal, String metalake, MetadataObject metadataObject) { + return true; + } + @Override public void close() throws IOException {} } diff --git a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationConverter.java b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationConverter.java deleted file mode 100644 index f9a8c7bcac..0000000000 --- a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationConverter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.gravitino.server.authorization.expression; - -import com.google.errorprone.annotations.DoNotCall; -import org.apache.gravitino.server.authorization.MetadataFilterHelper; - -public class AuthorizationConverter { - - private AuthorizationConverter() {} - - /** - * Convert the authorization expression to OGNL expression. <a - * href="https://github.com/orphan-oss/ognl">OGNL</a> stands for Object-Graph Navigation Language; - * It is an expression language for getting and setting properties of Java objects, plus other - * extras such as list projection and selection and lambda expressions. You use the same - * expression for both getting and setting the value of a property. - * - * @param authorizationExpression authorization expression from {@link MetadataFilterHelper} - * @return an OGNL expression used to call GravitinoAuthorizer - */ - @DoNotCall - public static String convertToOgnlExpression(String authorizationExpression) { - throw new UnsupportedOperationException(); - } -} diff --git a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java new file mode 100644 index 0000000000..858d9b4925 --- /dev/null +++ b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java @@ -0,0 +1,81 @@ +/* + * 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.gravitino.server.authorization.expression; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.gravitino.auth.AuthConstants; +import org.apache.gravitino.server.authorization.MetadataFilterHelper; + +/** + * Convert the authorization expression into an executable expression, such as OGNL expression, etc. + */ +public class AuthorizationExpressionConverter { + + /** Match authorization expressions */ + public static final Pattern PATTERN = Pattern.compile("([A-Z_]+)::([A-Z_]+)"); + + /** + * The EXPRESSION_CACHE caches the result of converting authorization expressions into an OGNL + * expression. + */ + private static final Map<String, String> EXPRESSION_CACHE = new ConcurrentHashMap<>(); + + private AuthorizationExpressionConverter() {} + + /** + * Convert the authorization expression to OGNL expression. <a + * href="https://github.com/orphan-oss/ognl">OGNL</a> stands for Object-Graph Navigation Language; + * It is an expression language for getting and setting properties of Java objects, plus other + * extras such as list projection and selection and lambda expressions. You use the same + * expression for both getting and setting the value of a property. + * + * @param authorizationExpression authorization expression from {@link MetadataFilterHelper} + * @return an OGNL expression used to call GravitinoAuthorizer + */ + public static String convertToOgnlExpression(String authorizationExpression) { + return EXPRESSION_CACHE.computeIfAbsent( + authorizationExpression, + (expression) -> { + Matcher matcher = PATTERN.matcher(expression); + StringBuffer result = new StringBuffer(); + + while (matcher.find()) { + String metadataType = matcher.group(1); + String privilegeOrOwner = matcher.group(2); + String replacement; + if (AuthConstants.OWNER.equals(privilegeOrOwner)) { + replacement = + String.format("authorizer.isOwner(principal,METALAKE_NAME,%s)", metadataType); + } else { + replacement = + String.format( + "authorizer.authorize(principal,METALAKE_NAME,%s," + + "@org.apache.gravitino.authorization.Privilege\\$Name@%s)", + metadataType, privilegeOrOwner); + } + matcher.appendReplacement(result, replacement); + } + matcher.appendTail(result); + + return result.toString(); + }); + } +} diff --git a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionEvaluator.java b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionEvaluator.java index f124ddaa47..3f4d429935 100644 --- a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionEvaluator.java +++ b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionEvaluator.java @@ -17,29 +17,78 @@ package org.apache.gravitino.server.authorization.expression; +import java.security.Principal; import java.util.Map; +import ognl.Ognl; +import ognl.OgnlContext; +import ognl.OgnlException; +import org.apache.commons.lang3.StringUtils; import org.apache.gravitino.MetadataObject; +import org.apache.gravitino.MetadataObjects; +import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.server.authorization.GravitinoAuthorizer; +import org.apache.gravitino.server.authorization.GravitinoAuthorizerProvider; +import org.apache.gravitino.utils.PrincipalUtils; -/** Evaluate the runtime result of the AuthorizationExpression.. */ +/** Evaluate the runtime result of the AuthorizationExpression. */ public class AuthorizationExpressionEvaluator { + private final String ognlAuthorizationExpression; + /** - * Use {@link AuthorizationConverter} to convert the authorization expression into an OGNL - * expression, and then call {@link GravitinoAuthorizer} to perform permission verification. + * Use {@link AuthorizationExpressionConverter} to convert the authorization expression into an + * OGNL expression, and then call {@link GravitinoAuthorizer} to perform permission verification. * * @param expression authorization expression */ - public AuthorizationExpressionEvaluator(String expression) {} + public AuthorizationExpressionEvaluator(String expression) { + this.ognlAuthorizationExpression = + AuthorizationExpressionConverter.convertToOgnlExpression(expression); + } /** * Use OGNL expressions to invoke GravitinoAuthorizer for authorizing multiple types of metadata * IDs. * - * @param metadataIds key-metadata type, value-metadata id + * @param metadataNames key-metadata type, value-metadata NameIdentifier * @return authorization result */ - public boolean evaluate(Map<MetadataObject.Type, Long> metadataIds) { - throw new UnsupportedOperationException(); + public boolean evaluate(Map<MetadataObject.Type, NameIdentifier> metadataNames) { + Principal currentPrincipal = PrincipalUtils.getCurrentPrincipal(); + GravitinoAuthorizer gravitinoAuthorizer = + GravitinoAuthorizerProvider.getInstance().getGravitinoAuthorizer(); + OgnlContext ognlContext = Ognl.createDefaultContext(null); + ognlContext.put("principal", currentPrincipal); + ognlContext.put("authorizer", gravitinoAuthorizer); + metadataNames.forEach( + (metadataType, metadataName) -> { + MetadataObject metadataObject = buildMetadataObject(metadataType, metadataName); + ognlContext.put(metadataType.name(), metadataObject); + }); + NameIdentifier nameIdentifier = metadataNames.get(MetadataObject.Type.METALAKE); + ognlContext.put("METALAKE_NAME", nameIdentifier.name()); + try { + Object value = Ognl.getValue(ognlAuthorizationExpression, ognlContext); + return (boolean) value; + } catch (OgnlException e) { + throw new RuntimeException("ognl evaluate error", e); + } + } + + /** + * Build the MetadataObject through metadataType and metadataName. + * + * @param metadataType metadata type + * @param metadataName metadata NameIdentifier + * @return MetadataObject + */ + private MetadataObject buildMetadataObject( + MetadataObject.Type metadataType, NameIdentifier metadataName) { + String namespaceWithMetalake = metadataName.namespace().toString(); + String metadataParent = StringUtils.substringAfter(namespaceWithMetalake, "."); + if ("".equals(metadataParent)) { + return MetadataObjects.of(null, metadataName.name(), metadataType); + } + return MetadataObjects.of(metadataParent, metadataName.name(), metadataType); } } diff --git a/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionConverter.java b/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionConverter.java new file mode 100644 index 0000000000..458c63336e --- /dev/null +++ b/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionConverter.java @@ -0,0 +1,80 @@ +/* + * 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.gravitino.server.authorization.expression; + +import static org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConverter.PATTERN; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** Test for {@link AuthorizationExpressionConverter} */ +public class TestAuthorizationExpressionConverter { + + /** Test for PATTERN. */ + @Test + public void testPattern() { + assertFalse(PATTERN.matcher("::").matches()); + assertFalse(PATTERN.matcher("KEY::").matches()); + assertFalse(PATTERN.matcher("::VALUE").matches()); + assertTrue(PATTERN.matcher("CATALOG::CREATE_TABLE").matches()); + } + + @Test + public void testConvertToOgnlWithoutOwnerExpression() { + String createTableAuthorizationExpression = "CATALOG::CREATE_TABLE || SCHEMA::CREATE_SCHEMA"; + String createTableOgnlExpression = + AuthorizationExpressionConverter.convertToOgnlExpression( + createTableAuthorizationExpression); + Assertions.assertEquals( + "authorizer.authorize(principal,METALAKE_NAME,CATALOG," + + "@org.apache.gravitino.authorization.Privilege$Name@CREATE_TABLE) " + + "|| authorizer.authorize(principal,METALAKE_NAME,SCHEMA," + + "@org.apache.gravitino.authorization.Privilege$Name@CREATE_SCHEMA)", + createTableOgnlExpression); + String selectTableAuthorizationExpression = + "CATALOG::USE_CATALOG && SCHEMA::USE_SCHEMA &&" + + " (TABLE::SELECT_TABLE || TABLE::MODIFY_TABLE)"; + String selectTableOgnlExpression = + AuthorizationExpressionConverter.convertToOgnlExpression( + selectTableAuthorizationExpression); + Assertions.assertEquals( + "authorizer.authorize(principal,METALAKE_NAME,CATALOG," + + "@org.apache.gravitino.authorization.Privilege$Name@USE_CATALOG) " + + "&& authorizer.authorize(principal,METALAKE_NAME,SCHEMA," + + "@org.apache.gravitino.authorization.Privilege$Name@USE_SCHEMA) " + + "&& (authorizer.authorize(principal,METALAKE_NAME,TABLE," + + "@org.apache.gravitino.authorization.Privilege$Name@SELECT_TABLE) " + + "|| authorizer.authorize(principal,METALAKE_NAME,TABLE," + + "@org.apache.gravitino.authorization.Privilege$Name@MODIFY_TABLE))", + selectTableOgnlExpression); + } + + @Test + public void testConvertToOgnlWithOwnerExpression() { + String expressionWithOwner = "CATALOG::CREATE_SCHEMA || SCHEMA::OWNER"; + String createTableOgnlExpression = + AuthorizationExpressionConverter.convertToOgnlExpression(expressionWithOwner); + Assertions.assertEquals( + "authorizer.authorize(principal,METALAKE_NAME,CATALOG," + + "@org.apache.gravitino.authorization.Privilege$Name@CREATE_SCHEMA) " + + "|| authorizer.isOwner(principal,METALAKE_NAME,SCHEMA)", + createTableOgnlExpression); + } +} diff --git a/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionEvaluator.java b/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionEvaluator.java new file mode 100644 index 0000000000..2d2386ac76 --- /dev/null +++ b/server-common/src/test/java/org/apache/gravitino/server/authorization/expression/TestAuthorizationExpressionEvaluator.java @@ -0,0 +1,149 @@ +/* + * 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.gravitino.server.authorization.expression; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.security.Principal; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.gravitino.MetadataObject; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.UserPrincipal; +import org.apache.gravitino.authorization.Privilege; +import org.apache.gravitino.server.authorization.GravitinoAuthorizer; +import org.apache.gravitino.server.authorization.GravitinoAuthorizerProvider; +import org.apache.gravitino.utils.NameIdentifierUtil; +import org.apache.gravitino.utils.PrincipalUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +/** Test for {@link AuthorizationExpressionEvaluator} */ +public class TestAuthorizationExpressionEvaluator { + + @Test + public void testEvaluator() { + String expression = + "CATALOG::USE_CATALOG && SCHEMA::USE_SCHEMA && (TABLE::SELECT_TABLE || TABLE::MODIFY_TABLE)"; + AuthorizationExpressionEvaluator authorizationExpressionEvaluator = + new AuthorizationExpressionEvaluator(expression); + try (MockedStatic<PrincipalUtils> principalUtilsMocked = mockStatic(PrincipalUtils.class); + MockedStatic<GravitinoAuthorizerProvider> mockStatic = + mockStatic(GravitinoAuthorizerProvider.class)) { + principalUtilsMocked + .when(PrincipalUtils::getCurrentPrincipal) + .thenReturn(new UserPrincipal("tester")); + GravitinoAuthorizerProvider mockedProvider = mock(GravitinoAuthorizerProvider.class); + mockStatic.when(GravitinoAuthorizerProvider::getInstance).thenReturn(mockedProvider); + when(mockedProvider.getGravitinoAuthorizer()).thenReturn(new MockGravitinoAuthorizer()); + Map<MetadataObject.Type, NameIdentifier> metadataNames = new HashMap<>(); + metadataNames.put( + MetadataObject.Type.METALAKE, NameIdentifierUtil.ofMetalake("testMetalake")); + metadataNames.put( + MetadataObject.Type.CATALOG, NameIdentifierUtil.ofCatalog("testMetalake", "testCatalog")); + metadataNames.put( + MetadataObject.Type.SCHEMA, + NameIdentifierUtil.ofSchema("testMetalake", "testCatalog", "testSchema")); + metadataNames.put( + MetadataObject.Type.TABLE, + NameIdentifierUtil.ofTable( + "testMetalake", "testCatalog", "testSchema", "testTableHasNotPermission")); + Assertions.assertFalse(authorizationExpressionEvaluator.evaluate(metadataNames)); + metadataNames.put( + MetadataObject.Type.TABLE, + NameIdentifierUtil.ofTable("testMetalake", "testCatalog", "testSchema", "testTable")); + Assertions.assertTrue(authorizationExpressionEvaluator.evaluate(metadataNames)); + } + } + + @Test + public void testEvaluatorWithOwner() { + String expression = "METALAKE::OWNER || CATALOG::CREATE_CATALOG"; + AuthorizationExpressionEvaluator authorizationExpressionEvaluator = + new AuthorizationExpressionEvaluator(expression); + try (MockedStatic<PrincipalUtils> principalUtilsMocked = mockStatic(PrincipalUtils.class); + MockedStatic<GravitinoAuthorizerProvider> mockStatic = + mockStatic(GravitinoAuthorizerProvider.class)) { + principalUtilsMocked + .when(PrincipalUtils::getCurrentPrincipal) + .thenReturn(new UserPrincipal("tester")); + GravitinoAuthorizerProvider mockedProvider = mock(GravitinoAuthorizerProvider.class); + mockStatic.when(GravitinoAuthorizerProvider::getInstance).thenReturn(mockedProvider); + when(mockedProvider.getGravitinoAuthorizer()).thenReturn(new MockGravitinoAuthorizer()); + Map<MetadataObject.Type, NameIdentifier> metadataNames = new HashMap<>(); + metadataNames.put( + MetadataObject.Type.METALAKE, NameIdentifierUtil.ofMetalake("metalakeWithOutOwner")); + metadataNames.put( + MetadataObject.Type.CATALOG, + NameIdentifierUtil.ofCatalog("metalakeWithOwner", "testCatalog")); + Assertions.assertFalse(authorizationExpressionEvaluator.evaluate(metadataNames)); + metadataNames.put( + MetadataObject.Type.METALAKE, NameIdentifierUtil.ofMetalake("metalakeWithOwner")); + Assertions.assertTrue(authorizationExpressionEvaluator.evaluate(metadataNames)); + } + } + + private static class MockGravitinoAuthorizer implements GravitinoAuthorizer { + + @Override + public void initialize() {} + + @Override + public boolean authorize( + Principal principal, + String metalake, + MetadataObject metadataObject, + Privilege.Name privilege) { + if (!("tester".equals(principal.getName()) && "testMetalake".equals(metalake))) { + return false; + } + String name = metadataObject.name(); + MetadataObject.Type type = metadataObject.type(); + if (type == MetadataObject.Type.CATALOG + && "testCatalog".equals(name) + && privilege == Privilege.Name.USE_CATALOG) { + return true; + } + if (type == MetadataObject.Type.SCHEMA + && "testSchema".equals(name) + && privilege == Privilege.Name.USE_SCHEMA) { + return true; + } + return type == MetadataObject.Type.TABLE + && "testTable".equals(name) + && privilege == Privilege.Name.SELECT_TABLE; + } + + @Override + public boolean isOwner(Principal principal, String metalake, MetadataObject metadataObject) { + if (!("tester".equals(principal.getName()) && "metalakeWithOwner".equals(metalake))) { + return false; + } + return Objects.equals(metadataObject.type(), MetadataObject.Type.METALAKE) + && Objects.equals("metalakeWithOwner", metadataObject.name()); + } + + @Override + public void close() throws IOException {} + } +}
