Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2C698EBDC for ; Tue, 28 May 2013 14:53:49 +0000 (UTC) Received: (qmail 83050 invoked by uid 500); 28 May 2013 14:53:49 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 83005 invoked by uid 500); 28 May 2013 14:53:48 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 82992 invoked by uid 99); 28 May 2013 14:53:48 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 May 2013 14:53:48 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 May 2013 14:53:43 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 2A39623889DE; Tue, 28 May 2013 14:53:22 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1486945 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/security/authorization/ main/java/org/apache/jackrabbit/oak/security/authorization/permission/ main/java/org/apache/jackrabbit/oak/spi/security/authorizat... Date: Tue, 28 May 2013 14:53:21 -0000 To: oak-commits@jackrabbit.apache.org From: angela@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130528145322.2A39623889DE@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: angela Date: Tue May 28 14:53:21 2013 New Revision: 1486945 URL: http://svn.apache.org/r1486945 Log: OAK-527: permissions (wip) Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConstants.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/ReadPolicyTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java?rev=1486945&r1=1486944&r2=1486945&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java Tue May 28 14:53:21 2013 @@ -43,6 +43,7 @@ import javax.jcr.security.NamedAccessCon import javax.jcr.security.Privilege; import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; @@ -122,7 +123,7 @@ public class AccessControlManagerImpl im restrictionProvider = acConfig.getRestrictionProvider(); ntMgr = ReadOnlyNodeTypeManager.getInstance(root, namePathMapper); - readPaths = acConfig.getParameters().getConfigValue(PARAM_READ_PATHS, DEFAULT_READ_PATHS); + readPaths = ImmutableSet.copyOf(acConfig.getParameters().getConfigValue(PARAM_READ_PATHS, DEFAULT_READ_PATHS)); } private static T getConfig(SecurityProvider sp, Class clss) { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1486945&r1=1486944&r2=1486945&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Tue May 28 14:53:21 2013 @@ -22,6 +22,7 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import com.google.common.collect.ImmutableSet; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Root; @@ -33,10 +34,10 @@ import org.apache.jackrabbit.oak.core.Im import org.apache.jackrabbit.oak.core.TreeTypeProvider; import org.apache.jackrabbit.oak.core.TreeTypeProviderImpl; import org.apache.jackrabbit.oak.plugins.version.VersionConstants; -import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConstants; import org.apache.jackrabbit.oak.security.privilege.PrivilegeBitsProvider; import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConstants; import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus; @@ -73,6 +74,7 @@ public class PermissionProviderImpl impl this.root = root; this.workspaceName = root.getContentSession().getWorkspaceName(); acConfig = securityProvider.getConfiguration(AccessControlConfiguration.class); + if (principals.contains(SystemPrincipal.INSTANCE) || isAdmin(principals)) { compiledPermissions = AllPermissions.getInstance(); } else { @@ -80,10 +82,11 @@ public class PermissionProviderImpl impl if (!permissionsTree.exists() || principals.isEmpty()) { compiledPermissions = NoPermissions.getInstance(); } else { + String[] readPaths = acConfig.getParameters().getConfigValue(AccessControlConstants.PARAM_READ_PATHS, AccessControlConstants.DEFAULT_READ_PATHS); compiledPermissions = new CompiledPermissionImpl(principals, permissionsTree, getBitsProvider(), acConfig.getRestrictionProvider(), - acConfig.getParameters().getConfigValue(AccessControlConstants.PARAM_READ_PATHS, AccessControlConstants.DEFAULT_READ_PATHS)); + ImmutableSet.copyOf(readPaths)); } } } @@ -175,9 +178,10 @@ public class PermissionProviderImpl impl //-------------------------------------------------------------------------- - private static boolean isAdmin(Set principals) { + private boolean isAdmin(Set principals) { + Set adminNames = ImmutableSet.copyOf(acConfig.getParameters().getConfigValue(PARAM_ADMINISTRATOR_PRINCIPALS, new String[0])); for (Principal principal : principals) { - if (principal instanceof AdminPrincipal) { + if (principal instanceof AdminPrincipal || adminNames.contains(principal.getName())) { return true; } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConstants.java?rev=1486945&r1=1486944&r2=1486945&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConstants.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConstants.java Tue May 28 14:53:21 2013 @@ -17,7 +17,6 @@ package org.apache.jackrabbit.oak.spi.security.authorization; import java.util.Collection; -import java.util.Set; import com.google.common.collect.ImmutableSet; import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants; @@ -118,8 +117,16 @@ public interface AccessControlConstants /** * Default value for the {@link #PARAM_READ_PATHS} configuration parameter. */ - Set DEFAULT_READ_PATHS = ImmutableSet.of( + String[] DEFAULT_READ_PATHS = new String[] { NamespaceConstants.NAMESPACES_PATH, NodeTypeConstants.NODE_TYPES_PATH, - PrivilegeConstants.PRIVILEGES_PATH); + PrivilegeConstants.PRIVILEGES_PATH + }; + + /** + * Configuration parameter specifying additional principals that should be + * treated as 'administrator' thus get granted full permissions on the + * complete repository content. + */ + String PARAM_ADMINISTRATOR_PRINCIPALS = "administratorPrincipals"; } Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/ReadPolicyTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/ReadPolicyTest.java?rev=1486945&r1=1486944&r2=1486945&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/ReadPolicyTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/ReadPolicyTest.java Tue May 28 14:53:21 2013 @@ -33,7 +33,7 @@ import static org.junit.Assert.assertTru */ public class ReadPolicyTest extends AbstractAccessControlTest { - private Set readPaths; + private String[] readPaths; @Override @Before Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java?rev=1486945&r1=1486944&r2=1486945&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java Tue May 28 14:53:21 2013 @@ -26,7 +26,6 @@ import java.util.Set; import javax.annotation.Nonnull; import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.oak.AbstractSecurityTest; @@ -84,9 +83,9 @@ public class CompiledPermissionImplTest private String node1Path = "/nodeName1"; private String node2Path = node1Path + "/nodeName2"; - private List allPaths; - private List rootAndUsers; - private List nodePaths; + private Set allPaths; + private Set rootAndUsers; + private Set nodePaths; @Before @Override @@ -114,9 +113,9 @@ public class CompiledPermissionImplTest testNode2.setString("propName2", "strValue"); root.commit(); - allPaths = ImmutableList.of("/", UserConstants.DEFAULT_USER_PATH, node1Path, node2Path); - rootAndUsers = ImmutableList.of("/", UserConstants.DEFAULT_USER_PATH); - nodePaths = ImmutableList.of(node1Path, node2Path); + allPaths = ImmutableSet.of("/", UserConstants.DEFAULT_USER_PATH, node1Path, node2Path); + rootAndUsers = ImmutableSet.of("/", UserConstants.DEFAULT_USER_PATH); + nodePaths = ImmutableSet.of(node1Path, node2Path); } @Override @@ -173,7 +172,7 @@ public class CompiledPermissionImplTest CompiledPermissionImpl cp = createPermissions(ImmutableSet.of(group1)); - assertReadStatus(DENY_THIS, DENY_THIS, cp, ImmutableList.of("/", node1Path, UserConstants.DEFAULT_USER_PATH)); + assertReadStatus(DENY_THIS, DENY_THIS, cp, ImmutableSet.of("/", node1Path, UserConstants.DEFAULT_USER_PATH)); assertReadStatus(ALLOW_ALL_REGULAR, ALLOW_THIS, cp, node2Path); } @@ -286,7 +285,7 @@ public class CompiledPermissionImplTest CompiledPermissionImpl cp = createPermissions(ImmutableSet.of(group1, group2)); - List treePaths = ImmutableList.of("/", UserConstants.DEFAULT_USER_PATH, node1Path); + Set treePaths = ImmutableSet.of("/", UserConstants.DEFAULT_USER_PATH, node1Path); assertReadStatus(DENY_THIS, DENY_THIS, cp, treePaths); assertReadStatus(ALLOW_NODES, DENY_THIS, cp, node2Path); } @@ -396,7 +395,7 @@ public class CompiledPermissionImplTest deny(group3, node1Path, 2, JCR_READ); CompiledPermissionImpl cp = createPermissions(ImmutableSet.of(group1)); - assertReadStatus(DENY_THIS, ALLOW_THIS, cp, ImmutableList.of(node1Path)); + assertReadStatus(DENY_THIS, ALLOW_THIS, cp, ImmutableSet.of(node1Path)); assertReadStatus(ALLOW_THIS, ALLOW_THIS, cp, node2Path); // TODO: need to change RestrictionPattern in order to get ALLOW_ALL_REGULAR cp = createPermissions(ImmutableSet.of(group1, group2)); @@ -424,7 +423,7 @@ public class CompiledPermissionImplTest allow(group1, node1Path, 2, new String[]{JCR_READ}, createGlobRestriction("/*")); CompiledPermissions cp = createPermissions(ImmutableSet.of(group1, group2, group3)); - assertReadStatus(DENY_THIS, ALLOW_THIS, cp, ImmutableList.of(node1Path)); + assertReadStatus(DENY_THIS, ALLOW_THIS, cp, ImmutableSet.of(node1Path)); assertReadStatus(ALLOW_THIS, ALLOW_THIS, cp, node2Path); } @@ -436,7 +435,7 @@ public class CompiledPermissionImplTest allow(group1, node1Path, 2, new String[]{REP_READ_PROPERTIES}, createGlobRestriction("/*")); CompiledPermissions cp = createPermissions(ImmutableSet.of(group1, group2, group3)); - assertReadStatus(ALLOW_THIS, DENY_THIS, cp, ImmutableList.of(node1Path)); + assertReadStatus(ALLOW_THIS, DENY_THIS, cp, ImmutableSet.of(node1Path)); assertReadStatus(ALLOW_THIS, ALLOW_THIS, cp, node2Path); } @@ -449,7 +448,7 @@ public class CompiledPermissionImplTest @Test public void testGetReadStatusForReadPaths() throws Exception { CompiledPermissionImpl cp = createPermissions(Collections.singleton(userPrincipal)); - assertReadStatus(ALLOW_ALL_REGULAR, ALLOW_ALL_REGULAR, cp, new ArrayList(DEFAULT_READ_PATHS)); + assertReadStatus(ALLOW_ALL_REGULAR, ALLOW_ALL_REGULAR, cp, ImmutableSet.copyOf(DEFAULT_READ_PATHS)); } @Test @@ -503,7 +502,7 @@ public class CompiledPermissionImplTest private CompiledPermissionImpl createPermissions(Set principals) { ImmutableTree permissionsTree = new ImmutableRoot(root, TreeTypeProvider.EMPTY).getTree(PERMISSIONS_STORE_PATH); - return new CompiledPermissionImpl(principals, permissionsTree, pbp, rp, DEFAULT_READ_PATHS); + return new CompiledPermissionImpl(principals, permissionsTree, pbp, rp, ImmutableSet.copyOf(DEFAULT_READ_PATHS)); } private void allow(Principal principal, String path, int index, String... privilegeNames) throws CommitFailedException { @@ -542,13 +541,13 @@ public class CompiledPermissionImplTest ReadStatus expectedProperties, CompiledPermissions cp, String treePath) { - assertReadStatus(expectedTrees, expectedTrees, cp, Collections.singletonList(treePath)); + assertReadStatus(expectedTrees, expectedTrees, cp, Collections.singleton(treePath)); } private void assertReadStatus(ReadStatus expectedTrees, ReadStatus expectedProperties, CompiledPermissions cp, - List treePaths) { + Set treePaths) { for (String path : treePaths) { Tree node = root.getTree(path); assertSame("Tree " + path, expectedTrees, cp.getReadStatus(node, null)); Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java?rev=1486945&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java Tue May 28 14:53:21 2013 @@ -0,0 +1,138 @@ +/* + * 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.jackrabbit.oak.security.authorization.permission; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.api.security.user.Group; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.oak.AbstractSecurityTest; +import org.apache.jackrabbit.oak.api.ContentSession; +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.core.ImmutableRoot; +import org.apache.jackrabbit.oak.core.TreeTypeProvider; +import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants; +import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants; +import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConstants; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants; +import org.apache.jackrabbit.oak.util.NodeUtil; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +public class PermissionProviderImplTest extends AbstractSecurityTest implements AccessControlConstants { + + private static final String ADMINISTRATOR_GROUP = "administrators"; + private static final String[] READ_PATHS = new String[] { + NamespaceConstants.NAMESPACES_PATH, + NodeTypeConstants.NODE_TYPES_PATH, + PrivilegeConstants.PRIVILEGES_PATH, + "/test" + }; + + private Group adminstrators; + + @Override + public void before() throws Exception { + super.before(); + + new NodeUtil(root.getTree("/")).addChild("test", JcrConstants.NT_UNSTRUCTURED); + UserManager uMgr = getUserManager(root); + adminstrators = uMgr.createGroup(ADMINISTRATOR_GROUP); + root.commit(); + } + + @Override + public void after() throws Exception { + try { + root.getTree("/test").remove(); + UserManager uMgr = getUserManager(root); + if (adminstrators != null) { + uMgr.getAuthorizable(adminstrators.getID()).remove(); + } + if (root.hasPendingChanges()) { + root.commit(); + } + } finally { + super.after(); + } + } + + @Override + protected ConfigurationParameters getSecurityConfigParameters() { + Map map = new HashMap(); + map.put(PARAM_READ_PATHS, READ_PATHS); + map.put(PARAM_ADMINISTRATOR_PRINCIPALS, new String[] {ADMINISTRATOR_GROUP}); + ConfigurationParameters acConfig = new ConfigurationParameters(map); + + return new ConfigurationParameters(ImmutableMap.of(AccessControlConfiguration.PARAM_ACCESS_CONTROL_OPTIONS, acConfig)); + } + + @Test + public void testReadPath() throws Exception { + ContentSession testSession = createTestSession(); + try { + Root r = testSession.getLatestRoot(); + Root immutableRoot = new ImmutableRoot(r, TreeTypeProvider.EMPTY); + + PermissionProvider pp = new PermissionProviderImpl(testSession.getLatestRoot(), testSession.getAuthInfo().getPrincipals(), getSecurityProvider()); + + assertFalse(r.getTree("/").exists()); + assertSame(ReadStatus.DENY_THIS, pp.getReadStatus(immutableRoot.getTree("/"), null)); + + for (String path : READ_PATHS) { + assertTrue(r.getTree(path).exists()); + assertSame(ReadStatus.ALLOW_ALL_REGULAR, pp.getReadStatus(immutableRoot.getTree(path), null)); + } + } finally { + testSession.close(); + } + } + + @Test + public void testAdministatorConfig() throws Exception { + adminstrators.addMember(getTestUser()); + root.commit(); + + ContentSession testSession = createTestSession(); + try { + Root r = testSession.getLatestRoot(); + Root immutableRoot = new ImmutableRoot(r, TreeTypeProvider.EMPTY); + + PermissionProvider pp = new PermissionProviderImpl(testSession.getLatestRoot(), testSession.getAuthInfo().getPrincipals(), getSecurityProvider()); + + assertTrue(r.getTree("/").exists()); + assertSame(ReadStatus.ALLOW_ALL, pp.getReadStatus(immutableRoot.getTree("/"), null)); + + for (String path : READ_PATHS) { + assertTrue(r.getTree(path).exists()); + assertSame(ReadStatus.ALLOW_ALL, pp.getReadStatus(immutableRoot.getTree(path), null)); + } + } finally { + testSession.close(); + } + } +} \ No newline at end of file