Skip to content

Commit 781456c

Browse files
authored
Merge pull request #106 from evolvedbinary/7.x.x/hotfix/security-metadata
[7.x.x] Fix an issue with de-serialization of Maps in the Configurator
2 parents b036b03 + 366cd2f commit 781456c

File tree

9 files changed

+625
-397
lines changed

9 files changed

+625
-397
lines changed

exist-core/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,8 @@
773773
<include>src/test/java/org/exist/xquery/functions/fn/ParsingFunctionsTest.java</include>
774774
<include>src/test/java/org/exist/xquery/functions/fn/transform/ConvertTest.java</include>
775775
<include>src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java</include>
776+
<include>src/test/java/org/exist/xquery/functions/securitymanager/AccountMetadataFunctionsTest.java</include>
777+
<include>src/test/java/org/exist/xquery/functions/securitymanager/SecurityManagerTestUtil.java</include>
776778
<include>src/main/java/org/exist/xquery/functions/system/FunctionAvailable.java</include>
777779
<include>src/test/java/org/exist/xquery/functions/xmldb/XMLDBStoreTest.java</include>
778780
<include>src/test/java/org/exist/xquery/functions/xquery3/SerializeTest.java</include>
@@ -1195,6 +1197,11 @@
11951197
<include>src/main/java/org/exist/xquery/functions/fn/transform/Transform.java</include>
11961198
<include>src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java</include>
11971199
<include>src/main/java/org/exist/xquery/functions/integer/WordPicture.java</include>
1200+
<include>src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java</include>
1201+
<include>src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java</include>
1202+
<include>src/test/java/org/exist/xquery/functions/securitymanager/GroupMembershipFunctionRemoveGroupMemberTest.java</include>
1203+
<include>src/test/java/org/exist/xquery/functions/securitymanager/PermissionsFunctionChmodTest.java</include>
1204+
<include>src/test/java/org/exist/xquery/functions/securitymanager/PermissionsFunctionChownTest.java</include>
11981205
<include>src/main/java/org/exist/xquery/functions/system/GetUptime.java</include>
11991206
<include>src/main/java/org/exist/xquery/functions/system/Shutdown.java</include>
12001207
<include>src/main/java/org/exist/xquery/functions/system/SystemModule.java</include>
@@ -1792,6 +1799,13 @@
17921799
<exclude>src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java</exclude>
17931800
<exclude>src/main/java/org/exist/xquery/functions/integer/WordPicture.java</exclude>
17941801
<exclude>src/main/java/org/exist/xquery/functions/map/MapType.java</exclude>
1802+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/AccountMetadataFunctionsTest.java</exclude>
1803+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java</exclude>
1804+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java</exclude>
1805+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/GroupMembershipFunctionRemoveGroupMemberTest.java</exclude>
1806+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/PermissionsFunctionChmodTest.java</exclude>
1807+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/PermissionsFunctionChownTest.java</exclude>
1808+
<exclude>src/test/java/org/exist/xquery/functions/securitymanager/SecurityManagerTestUtil.java</exclude>
17951809
<exclude>src/test/java/org/exist/xquery/functions/session/AbstractSessionTest.java</exclude>
17961810
<exclude>src/test/java/org/exist/xquery/functions/session/AttributeTest.java</exclude>
17971811
<exclude>src/main/java/org/exist/xquery/functions/system/FunctionAvailable.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+
}

exist-core/src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
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+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*

exist-core/src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java

Lines changed: 34 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
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+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -21,23 +45,19 @@
2145
*/
2246
package org.exist.xquery.functions.securitymanager;
2347

24-
import com.evolvedbinary.j8fu.function.Runnable3E;
2548
import org.exist.EXistException;
2649
import org.exist.security.*;
2750
import org.exist.security.SecurityManager;
28-
import org.exist.security.internal.aider.GroupAider;
29-
import org.exist.security.internal.aider.UserAider;
3051
import org.exist.storage.BrokerPool;
3152
import org.exist.storage.DBBroker;
3253
import org.exist.storage.txn.Txn;
3354
import org.exist.test.ExistEmbeddedServer;
3455
import org.exist.xquery.XPathException;
35-
import org.exist.xquery.XQuery;
36-
import org.exist.xquery.value.Sequence;
3756
import org.junit.*;
3857

3958
import java.util.Optional;
4059

60+
import static org.exist.xquery.functions.securitymanager.SecurityManagerTestUtil.*;
4161
import static org.junit.Assert.*;
4262

4363
public class GroupManagementFunctionRemoveGroupTest {
@@ -55,17 +75,23 @@ public class GroupManagementFunctionRemoveGroupTest {
5575

5676
@Test(expected = PermissionDeniedException.class)
5777
public void cannotDeleteDbaGroup() throws XPathException, PermissionDeniedException, EXistException {
58-
extractPermissionDenied(() -> xqueryRemoveGroup(SecurityManager.DBA_GROUP));
78+
extractPermissionDenied(() -> {
79+
xqueryRemoveGroup(existWebServer.getBrokerPool(), SecurityManager.DBA_GROUP);
80+
});
5981
}
6082

6183
@Test(expected = PermissionDeniedException.class)
6284
public void cannotDeleteGuestGroup() throws XPathException, PermissionDeniedException, EXistException {
63-
extractPermissionDenied(() -> xqueryRemoveGroup(SecurityManager.GUEST_GROUP));
85+
extractPermissionDenied(() -> {
86+
xqueryRemoveGroup(existWebServer.getBrokerPool(), SecurityManager.GUEST_GROUP);
87+
});
6488
}
6589

6690
@Test(expected = PermissionDeniedException.class)
6791
public void cannotDeleteUnknownGroup() throws XPathException, PermissionDeniedException, EXistException {
68-
extractPermissionDenied(() -> xqueryRemoveGroup(SecurityManager.UNKNOWN_GROUP));
92+
extractPermissionDenied(() -> {
93+
xqueryRemoveGroup(existWebServer.getBrokerPool(), SecurityManager.UNKNOWN_GROUP);
94+
});
6995
}
7096

7197
@Test
@@ -258,69 +284,4 @@ public void deleteUsersSharingPersonalPrimaryGroup() throws PermissionDeniedExce
258284
transaction.commit();
259285
}
260286
}
261-
262-
private static Account createUser(final DBBroker broker, final SecurityManager sm, final String username, final String password) throws PermissionDeniedException, EXistException {
263-
Group userGroup = new GroupAider(username);
264-
sm.addGroup(broker, userGroup);
265-
final Account user = new UserAider(username);
266-
user.setPassword(password);
267-
user.setPrimaryGroup(userGroup);
268-
sm.addAccount(user);
269-
270-
userGroup = sm.getGroup(username);
271-
userGroup.addManager(sm.getAccount(username));
272-
sm.updateGroup(userGroup);
273-
274-
return user;
275-
}
276-
277-
private static Group createGroup(final DBBroker broker, final SecurityManager sm, final String groupName) throws PermissionDeniedException, EXistException {
278-
final Group otherGroup = new GroupAider(groupName);
279-
return sm.addGroup(broker, otherGroup);
280-
}
281-
282-
private static void addUserToGroup(final SecurityManager sm, final Account user, final Group group) throws PermissionDeniedException, EXistException {
283-
user.addGroup(group.getName());
284-
sm.updateAccount(user);
285-
}
286-
287-
private static void setPrimaryGroup(final SecurityManager sm, final Account user, final Group group) throws PermissionDeniedException, EXistException {
288-
user.setPrimaryGroup(group);
289-
sm.updateAccount(user);
290-
}
291-
292-
private static void removeUser(final SecurityManager sm, final String username) throws PermissionDeniedException, EXistException {
293-
sm.deleteAccount(username);
294-
removeGroup(sm, username);
295-
}
296-
297-
private static void removeGroup(final SecurityManager sm, final String groupname) throws PermissionDeniedException, EXistException {
298-
sm.deleteGroup(groupname);
299-
}
300-
301-
private Sequence xqueryRemoveGroup(final String groupname) throws EXistException, PermissionDeniedException, XPathException {
302-
final BrokerPool pool = existWebServer.getBrokerPool();
303-
304-
final String query =
305-
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
306-
"sm:remove-group('" + groupname + "')";
307-
308-
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
309-
final XQuery xquery = existWebServer.getBrokerPool().getXQueryService();
310-
final Sequence result = xquery.execute(broker, query, null);
311-
return result;
312-
}
313-
}
314-
315-
private static void extractPermissionDenied(final Runnable3E<XPathException, PermissionDeniedException, EXistException> runnable) throws XPathException, PermissionDeniedException, EXistException {
316-
try {
317-
runnable.run();
318-
} catch (final XPathException e) {
319-
if (e.getCause() != null && e.getCause() instanceof PermissionDeniedException) {
320-
throw (PermissionDeniedException)e.getCause();
321-
} else {
322-
throw e;
323-
}
324-
}
325-
}
326287
}

0 commit comments

Comments
 (0)