Skip to content

Commit 5385228

Browse files
committed
[bugfix] Make sure that single map entries are not lost when configuring instances from XML
Closes eXist-db/exist#5904
1 parent e77a95c commit 5385228

File tree

3 files changed

+154
-10
lines changed

3 files changed

+154
-10
lines changed

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@
724724
<include>src/test/java/org/exist/xquery/functions/fn/ParsingFunctionsTest.java</include>
725725
<include>src/test/java/org/exist/xquery/functions/fn/transform/ConvertTest.java</include>
726726
<include>src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java</include>
727+
<include>src/test/java/org/exist/xquery/functions/securitymanager/AccountMetadataFunctionsTest.java</include>
727728
<include>src/test/java/org/exist/xquery/functions/securitymanager/SecurityManagerTestUtil.java</include>
728729
<include>src/main/java/org/exist/xquery/functions/system/FunctionAvailable.java</include>
729730
<include>src/test/java/org/exist/xquery/functions/xmldb/XMLDBStoreTest.java</include>
@@ -1621,6 +1622,7 @@
16211622
<exclude>src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java</exclude>
16221623
<exclude>src/main/java/org/exist/xquery/functions/integer/WordPicture.java</exclude>
16231624
<exclude>src/main/java/org/exist/xquery/functions/map/MapType.java</exclude>
1625+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/AccountMetadataFunctionsTest.java</exclude>
16241626
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java</exclude>
16251627
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java</exclude>
16261628
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GroupMembershipFunctionRemoveGroupMemberTest.java</exclude>

exist-core/src/main/java/org/exist/config/ConfigurationImpl.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,20 @@ private void cache() {
146146
Node child = element.getFirstChild();
147147
while (child != null) {
148148

149-
if (child.getNodeType() == Node.ELEMENT_NODE) {
149+
if (child instanceof Element) {
150+
final Element childElement = (Element) child;
150151

151-
final String ns = child.getNamespaceURI();
152-
if (ns != null && NS.equals(ns)) {
153-
154-
String name = child.getLocalName();
152+
final String ns = childElement.getNamespaceURI();
153+
if (NS.equals(ns)) {
155154

155+
final String name = childElement.getLocalName();
156+
156157
if (names.contains(name)) {
157-
158-
if (props.containsKey(name)) {
159-
props.remove(name);
160-
}
158+
props.remove(name);
161159
} else {
162-
props.put(name, child.getTextContent());
160+
if (!childElement.hasAttribute("key")) { // NOTE(AR) Skip Map entries
161+
props.put(name, childElement.getTextContent());
162+
}
163163
names.add(name);
164164
}
165165
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
package org.exist.xquery.functions.securitymanager;
22+
23+
import org.exist.EXistException;
24+
import org.exist.collections.Collection;
25+
import org.exist.security.AXSchemaType;
26+
import org.exist.security.PermissionDeniedException;
27+
import org.exist.security.SecurityManager;
28+
import org.exist.security.internal.RealmImpl;
29+
import org.exist.storage.BrokerPool;
30+
import org.exist.storage.DBBroker;
31+
import org.exist.storage.txn.Txn;
32+
import org.exist.test.ExistEmbeddedServer;
33+
import org.exist.util.LockException;
34+
import org.exist.util.MimeType;
35+
import org.exist.util.StringInputSource;
36+
import org.exist.xmldb.XmldbURI;
37+
import org.exist.xquery.XPathException;
38+
import org.exist.xquery.XQuery;
39+
import org.exist.xquery.value.Sequence;
40+
import org.junit.Rule;
41+
import org.junit.Test;
42+
import org.xml.sax.SAXException;
43+
44+
import java.io.IOException;
45+
import java.util.Arrays;
46+
import java.util.Optional;
47+
48+
import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple;
49+
import static org.exist.xquery.functions.securitymanager.SecurityManagerTestUtil.*;
50+
import static org.junit.Assert.assertEquals;
51+
import static org.junit.Assert.assertNotNull;
52+
53+
public class AccountMetadataFunctionsTest {
54+
55+
private static final String USER1_NAME = "User 1";
56+
private static final String USER1_UID = "user1";
57+
private static final String USER1_PWD = USER1_UID;
58+
59+
@Rule
60+
public final ExistEmbeddedServer existWebServer = new ExistEmbeddedServer(true, true);
61+
62+
/**
63+
* Creates a new user programmatically and tries to retrieve their name
64+
* from the user's metadata.
65+
*
66+
* See: <a href="https://github.com/eXist-db/exist/issues/5904">[BUG] Security Account Metadata is lost</a>
67+
*/
68+
@Test
69+
public void getAccountNameMetadataViaObject() throws PermissionDeniedException, EXistException, XPathException {
70+
final BrokerPool pool = existWebServer.getBrokerPool();
71+
final SecurityManager sm = pool.getSecurityManager();
72+
73+
// 1. Create user
74+
try (final DBBroker broker = pool.get(Optional.of(sm.getSystemSubject()));
75+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
76+
createUser(broker, sm, USER1_UID, USER1_PWD, Arrays.asList(Tuple(AXSchemaType.FULLNAME, USER1_NAME)));
77+
transaction.commit();
78+
}
79+
80+
// 2. Try and retrieve the user's metadata from XQuery
81+
final String query =
82+
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
83+
"sm:get-account-metadata('" + USER1_UID + "', xs:anyURI('http://axschema.org/namePerson'))";
84+
85+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
86+
final XQuery xquery = existWebServer.getBrokerPool().getXQueryService();
87+
final Sequence result = xquery.execute(broker, query, null);
88+
assertNotNull(result);
89+
assertEquals(USER1_NAME, result.itemAt(0).getStringValue());
90+
}
91+
}
92+
93+
/**
94+
* Creates a new user by storing their account document into the security collection
95+
* and tries to retrieve their name from the user's metadata.
96+
*
97+
* See: <a href="https://github.com/eXist-db/exist/issues/5904">[BUG] Security Account Metadata is lost</a>
98+
*/
99+
@Test
100+
public void getAccountNameMetadataViaDocument() throws PermissionDeniedException, EXistException, XPathException, LockException, IOException, SAXException {
101+
final BrokerPool pool = existWebServer.getBrokerPool();
102+
final SecurityManager sm = pool.getSecurityManager();
103+
104+
final XmldbURI accountDocumentUri = XmldbURI.create(USER1_UID + ".xml");
105+
final String accountDocument =
106+
"<account xmlns=\"http://exist-db.org/Configuration\" id=\"15\">\n" +
107+
" <group name=\"nogroup\"/>\n" +
108+
" <password>{RIPEMD160}q2VXP75jMi+d8E5VAsEr6pD8V5w=</password>\n" +
109+
" <expired>false</expired>\n" +
110+
" <enabled>true</enabled>\n" +
111+
" <umask>022</umask>\n" +
112+
" <metadata key=\"http://axschema.org/namePerson\">" + USER1_NAME + "</metadata>\n" +
113+
" <name>" + USER1_UID + "</name>\n" +
114+
"</account>";
115+
116+
// 1. Create user
117+
try (final DBBroker broker = pool.get(Optional.of(sm.getSystemSubject()));
118+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
119+
120+
// /db/system/security/exist/accounts
121+
122+
final XmldbURI accountsCollectionUri = SecurityManager.SECURITY_COLLECTION_URI.append(RealmImpl.ID).append(SecurityManager.ACCOUNTS_COLLECTION_URI);
123+
124+
try (final Collection accountsCollection = broker.getCollection(accountsCollectionUri)) {
125+
accountsCollection.storeDocument(transaction, broker, accountDocumentUri, new StringInputSource(accountDocument), MimeType.XML_TYPE);
126+
}
127+
transaction.commit();
128+
}
129+
130+
// 2. Try and retrieve the user's metadata from XQuery
131+
final String query =
132+
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
133+
"sm:get-account-metadata('" + USER1_UID + "', xs:anyURI('http://axschema.org/namePerson'))";
134+
135+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
136+
final XQuery xquery = existWebServer.getBrokerPool().getXQueryService();
137+
final Sequence result = xquery.execute(broker, query, null);
138+
assertNotNull(result);
139+
assertEquals(USER1_NAME, result.itemAt(0).getStringValue());
140+
}
141+
}
142+
}

0 commit comments

Comments
 (0)