Compare commits

..

68 Commits
11.128 ... 12.7

Author SHA1 Message Date
Travis CI User
50f26b9137 [maven-release-plugin][skip ci] prepare release 12.7 2021-11-22 14:15:02 +00:00
evasques
b6b1cc3ea0 MNT-18700 - Dynamic Message bundles do not deploy/reload automatically (#805) (#810)
* Restored the ability to register dynamic messages on bootstrap
* Added unit tests on bootstrap to verify if the dynamic messages are registered on bootstrap
* Added unit tests for the Repo Admin Console regarding registering dynamic messages and classpath files

(cherry picked from commit be4fa79c76)
2021-11-22 10:35:27 +00:00
Travis CI User
0f1c1cdba1 [maven-release-plugin][skip ci] prepare for next development iteration 2021-11-17 22:20:28 +00:00
Travis CI User
841bc6844e [maven-release-plugin][skip ci] prepare release 12.6 2021-11-17 22:20:25 +00:00
tiagosalvado10
a5bdf47f00 [PRODSEC-5795] Bump surf-webscripts to 8.25 (#803) (#804)
(cherry picked from commit ee07bb635f)
2021-11-17 21:28:16 +00:00
Travis CI User
a0b279d1ff [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-25 14:21:26 +00:00
Travis CI User
fb967dfa9e [maven-release-plugin][skip ci] prepare release 12.5 2021-10-25 14:21:23 +00:00
Aleksandra Onych
f0a51e1347 MNT-21883 - Fix unshare content from smart folder (#765) (#772) 2021-10-25 15:00:23 +02:00
Travis CI User
42d56f9d20 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-19 11:04:24 +00:00
Travis CI User
3f31e4b1a2 [maven-release-plugin][skip ci] prepare release 12.4 2021-10-19 11:04:21 +00:00
Lev Belava
787a331869 MNT-21706 NodeService setAssociations list of elements is now handled. (#746) (#755)
MNT-21706 NodeService setAssociations list of elements is now handled.

(cherry picked from commit cbd45fcb3e)
2021-10-19 12:14:44 +02:00
Travis CI User
5ce3a3ddd6 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-06 11:41:46 +00:00
Travis CI User
9ed96ec593 [maven-release-plugin][skip ci] prepare release 12.3 2021-10-06 11:41:43 +00:00
montgolfiere
03b1fa8b09 ACS-2067: Fix probes for when DAU enabled (#700)
(cherry picked from commit 2ef97e0b23)
2021-10-06 11:38:04 +01:00
Travis CI User
d69f9b52c3 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-01 10:30:56 +00:00
Travis CI User
72b910bb48 [maven-release-plugin][skip ci] prepare release 12.2 2021-10-01 10:30:53 +00:00
evasques
cfaf3b280b MNT-22600 Nodes with security marks appear unfiltered on CMIS DB queries (#702) (#705)
* Change isUnfiltered to protected so we can extend it in enterprise
* Added test method to be able to do a cmis query test

Original commit in governance-services: e4e3235328

(cherry picked from commit c5281d7f10)
2021-10-01 10:18:01 +01:00
Travis CI User
00d814ec55 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-29 13:39:07 +00:00
Travis CI User
becabb3a41 [maven-release-plugin][skip ci] prepare release 12.1 2021-09-29 13:39:04 +00:00
Piotr Żurek
033157800b MNT-22611 - Fix bulk import parameters parsing (#699)
Cherry-picked from 85a3c71849  master to 7.1.N (7.1.1)
2021-09-29 14:39:28 +02:00
Travis CI User
b9c8ff91e4 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-28 22:58:13 +00:00
Travis CI User
c54d46ab67 [maven-release-plugin][skip ci] prepare release 12.0 2021-09-28 22:58:10 +00:00
alandavis
dec514c5c2 Missing files from last commit 2021-09-28 23:07:16 +01:00
alandavis
7c5a8a1963 Get master ready for 7.1.1 development 2021-09-28 23:05:39 +01:00
Travis CI User
559171a32c [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-27 13:36:15 +00:00
Travis CI User
b9f449df57 [maven-release-plugin][skip ci] prepare release 11.140 2021-09-27 13:36:12 +00:00
Travis CI User
3185ecf6cb [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-24 12:21:31 +00:00
Travis CI User
bd7f2a4250 [maven-release-plugin][skip ci] prepare release 11.139 2021-09-24 12:21:28 +00:00
Vitor Moreira
79efa12b10 Revert "MNT-22428: configurable unsecure jsonp callback CMIS operation (#698)"
This reverts commit 5807e756bd.
2021-09-24 11:25:05 +01:00
Vítor Moreira
5807e756bd MNT-22428: configurable unsecure jsonp callback CMIS operation (#698)
* MNT-22428: configurable unsecure jsonp callback CMIS operation
2021-09-23 15:57:23 +01:00
Travis CI User
6ecb019b84 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-16 12:38:24 +00:00
Travis CI User
c26f933c44 [maven-release-plugin][skip ci] prepare release 11.138 2021-09-16 12:38:20 +00:00
Jamal Kaabi-Mofrad
43e528878e ACS-1989: Fixed PostgreSQL patch. 2021-09-16 12:27:20 +01:00
Suneet Gupta
b120a9658f Revert "Releasing version 11.138"
This reverts commit 923261d9b9.
2021-09-16 16:36:30 +05:30
Suneet Gupta
3875a84f74 Revert "Releasing version 11.138"
This reverts commit 6f8507ebe2.
2021-09-16 16:36:28 +05:30
Suneet Gupta
8dddf293d0 Revert "Releasing version 11.138"
This reverts commit d01e9ffbbc.
2021-09-16 16:36:27 +05:30
Suneet Gupta
d01e9ffbbc Releasing version 11.138 2021-09-16 15:08:32 +05:30
Suneet Gupta
6f8507ebe2 Releasing version 11.138 2021-09-16 12:50:54 +05:30
Suneet Gupta
923261d9b9 Releasing version 11.138 2021-09-16 12:05:32 +05:30
Travis CI User
078e461b71 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-15 14:51:33 +00:00
Travis CI User
ddde92ef21 [maven-release-plugin][skip ci] prepare release 11.137 2021-09-15 14:51:29 +00:00
Miguel Ruiz
189011d528 Bump up api-explorer to 7.1.0.1 (#694) 2021-09-15 13:13:44 +01:00
Travis CI User
af849d2144 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-14 14:27:27 +00:00
Travis CI User
53208f207c [maven-release-plugin][skip ci] prepare release 11.136 2021-09-14 14:27:24 +00:00
alandavis
4cf3f77824 Pick up api-explorer 7.1.0 2021-09-14 14:15:46 +01:00
Travis CI User
9d24e083bb [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-13 07:13:40 +00:00
Travis CI User
6345c0a825 [maven-release-plugin][skip ci] prepare release 11.135 2021-09-13 07:13:37 +00:00
Sara Aspery
cda3d11c7e ACS-1981 fix DAUs status log 2021-09-13 06:51:56 +01:00
Travis CI User
7ad35ac60d [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-10 10:39:58 +00:00
Travis CI User
a164917232 [maven-release-plugin][skip ci] prepare release 11.134 2021-09-10 10:39:55 +00:00
Piotr Żurek
507c6b2ed8 ACS-1970 Switch to the alfresco/alfresco-base-tomcat:9.0.52-java-11-centos-7 base image (#693) 2021-09-10 11:13:53 +02:00
Travis CI User
ab0d65897c [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-07 11:57:08 +00:00
Travis CI User
d92844cebb [maven-release-plugin][skip ci] prepare release 11.133 2021-09-07 11:57:05 +00:00
dependabot-preview[bot]
25986d77d6 Bump commons-io from 2.8.0 to 2.11.0 (#597) 2021-09-07 11:08:17 +00:00
Travis CI User
2b8948b84b [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-02 14:45:02 +00:00
Travis CI User
64bf49cc22 [maven-release-plugin][skip ci] prepare release 11.132 2021-09-02 14:44:59 +00:00
Jamal Kaabi-Mofrad
3ce95c5262 REPO-5664/REPO-5665: System admin webscripts (#690) 2021-09-02 13:59:38 +01:00
Travis CI User
e854a01988 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-02 12:41:48 +00:00
Travis CI User
65ba8b16e0 [maven-release-plugin][skip ci] prepare release 11.131 2021-09-02 12:41:45 +00:00
mikolajbrzezinski
d2bb3a980d Feature/acs 1835 test dau for deleted renditions (#689)
* Deleted Renditions DAU Test Skeleton

* Deleted Renditions DAU Test v1

* Deleted Renditions DAU Test v2

* Deleted Renditions DAU Test v3

* Deleted Renditions DAU Test v3.1

* Comments From Pull Request
2021-09-02 13:50:17 +02:00
Gloria Camino
59b641474f LOC-329 - Fixed, updated UI files in 15 languages as per RM-6941 (#691) 2021-09-02 17:17:01 +05:30
Travis CI User
9ee56762fb [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-02 09:09:36 +00:00
Travis CI User
6cb8e84ee4 [maven-release-plugin][skip ci] prepare release 11.130 2021-09-02 09:09:33 +00:00
alandavis
d540bb319b Pick up latest tas-restapi 1.64 2021-09-02 09:48:07 +01:00
Travis CI User
30a2bff92a [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-01 22:17:42 +00:00
Travis CI User
ac08612183 [maven-release-plugin][skip ci] prepare release 11.129 2021-09-01 22:17:39 +00:00
alandavis
031d1c740c ACS-1924 Pick up api-explorer 7.1.0-A4
Includes changes for other Direct Access URI tickets
2021-09-01 21:58:19 +01:00
Travis CI User
aac73e2064 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-01 19:00:48 +00:00
87 changed files with 2045 additions and 747 deletions

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>

View File

@@ -619,11 +619,27 @@ public class BaseRMRestTest extends RestTest
* @return
*/
public List<String> searchForContentAsUser(UserModel user, String term)
{
String query = "cm:name:*" + term + "*";
return searchForContentAsUser(user,query,"afts");
}
/**
* Returns search results for the given search term
*
* @param user
* @param term
* @param query language
* @return
* @throws Exception
*/
public List<String> searchForContentAsUser(UserModel user, String q, String queryLanguage)
{
getRestAPIFactory().getRmRestWrapper().authenticateUser(user);
RestRequestQueryModel queryReq = new RestRequestQueryModel();
SearchRequest query = new SearchRequest(queryReq);
queryReq.setQuery("cm:name:*" + term + "*");
queryReq.setQuery(q);
queryReq.setLanguage(queryLanguage);
List<String> names = new ArrayList<>();
// wait for solr indexing

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Nelze vytv\u00e1\u0159et
rm.action.create.transfer.child-error-message=Nelze vytv\u00e1\u0159et polo\u017eky ve slo\u017ece p\u0159enosu.
rm.action.create.record.folder.child-error-message=Z\u00e1znamy je mo\u017en\u00e9 vytv\u00e1\u0159et pouze ve slo\u017ek\u00e1ch z\u00e1znam\u016f a toto bylo {0}.
rm.action.transfer-non-editable=Nelze upravovat metadata kontejneru nebo slo\u017eky pro p\u0159enos.
rm.action.node.frozen.error-message=Akci {0} nelze prov\u00e9st, proto\u017ee uzel je zablokovan\u00fd nebo m\u00e1 zablokovan\u00e9 pod\u0159\u00edzen\u00e9 prvky.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Du kan ikke oprette elem
rm.action.create.transfer.child-error-message=Du kan ikke oprette elementer i Overf\u00f8r-mapper.
rm.action.create.record.folder.child-error-message=Du kan kun oprette poster i postmapper, og dette var en {0}.
rm.action.transfer-non-editable=Du kan ikke redigere overf\u00f8rselsmappe- eller container-metadata.
rm.action.node.frozen.error-message=Handlingen kan ikke udf\u00f8res {0}, fordi noden er l\u00e5st eller har l\u00e5ste underordnede noder.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Sie k\u00f6nnen keine El
rm.action.create.transfer.child-error-message=Sie k\u00f6nnen keine Elemente in \u00dcbertragungsordnern erstellen.
rm.action.create.record.folder.child-error-message=In Record-Ordnern k\u00f6nnen Sie nur Records erstellen. Das war aber ein {0}.
rm.action.transfer-non-editable=Sie k\u00f6nnen Metadaten von \u00dcbertragungsordnern oder -containern nicht bearbeiten.
rm.action.node.frozen.error-message=Die Aktion ''{0}'' kann nicht ausgef\u00fchrt werden, da der Knoten oder untergeordnete Elemente von ihm festgefahren ist bzw. sind.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=No se pueden crear eleme
rm.action.create.transfer.child-error-message=No se pueden crear elementos en las carpetas de transferencia.
rm.action.create.record.folder.child-error-message=Solo puede crear documentos de archivo en carpetas de documentos de archivo. {0} no se puede crear aqu\u00ed.
rm.action.transfer-non-editable=No se puede editar una carpeta de transferencia ni los metadatos de un contenedor.
rm.action.node.frozen.error-message=No se puede realizar la acci\u00f3n {0} porque el nodo est\u00e1 congelado o tiene elementos secundarios congelados.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Siirtos\u00e4ili\u00f6\u
rm.action.create.transfer.child-error-message=Siirtokansioihin ei voi luoda kohteita.
rm.action.create.record.folder.child-error-message=Tietuekansioihin voi luoda ainoastaan tietueita, mutta t\u00e4m\u00e4 oli {0}.
rm.action.transfer-non-editable=Siirtokansion tai -s\u00e4ili\u00f6n metatietoja ei voi muokata.
rm.action.node.frozen.error-message=Toimintoa {0} ei voitu suorittaa, koska solmu on j\u00e4\u00e4dytetty tai sill\u00e4 on j\u00e4\u00e4dytettyj\u00e4 alatasoja.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Impossible de cr\u00e9er
rm.action.create.transfer.child-error-message=Impossible de cr\u00e9er des \u00e9l\u00e9ments dans les dossiers de transfert.
rm.action.create.record.folder.child-error-message=Vous ne pouvez cr\u00e9er des documents d''archives que dans les dossiers d''archives, dans le cas pr\u00e9sent {0}.
rm.action.transfer-non-editable=Impossible de modifier les m\u00e9tadonn\u00e9es de dossier de transfert ou de contenant.
rm.action.node.frozen.error-message=Impossible d''effectuer l''action {0} car le n\u0153ud ou ses enfants sont gel\u00e9s.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Impossibile creare eleme
rm.action.create.transfer.child-error-message=Impossibile creare elementi nelle cartelle Trasferimento.
rm.action.create.record.folder.child-error-message=I record possono essere creati solo nelle cartelle dei record e questa era {0}.
rm.action.transfer-non-editable=Impossibile modificare la cartella di trasferimento o i metadati dei contenitori.
rm.action.node.frozen.error-message=Impossibile eseguire l''azione {0} poich\u00e9 il nodo \u00e8 congelato o presenta nodi figlio congelati.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=\u8ee2\u9001\u30b3\u30f3
rm.action.create.transfer.child-error-message=\u8ee2\u9001\u30d5\u30a9\u30eb\u30c0\u5185\u3067\u306f\u30a2\u30a4\u30c6\u30e0\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002
rm.action.create.record.folder.child-error-message=\u30ec\u30b3\u30fc\u30c9\u3092\u4f5c\u6210\u3067\u304d\u308b\u306e\u306f\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u5185\u306e\u307f\u3067\u3001\u3053\u308c\u306f {0} \u3067\u3059\u3002
rm.action.transfer-non-editable=\u8ee2\u9001\u30d5\u30a9\u30eb\u30c0\u307e\u305f\u306f\u30b3\u30f3\u30c6\u30ca\u30e1\u30bf\u30c7\u30fc\u30bf\u306f\u7de8\u96c6\u3067\u304d\u307e\u305b\u3093\u3002
rm.action.node.frozen.error-message=\u30ce\u30fc\u30c9\u304c\u30d5\u30ea\u30fc\u30ba\u3057\u3066\u3044\u308b\u304b\u3001\u307e\u305f\u306f\u5b50\u304c\u51cd\u7d50\u3057\u3066\u3044\u308b\u305f\u3081\u3001\u30a2\u30af\u30b7\u30e7\u30f3 {0}\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Elementer kan ikke oppre
rm.action.create.transfer.child-error-message=Elementer kan ikke opprettes i overf\u00f8ringsmapper.
rm.action.create.record.folder.child-error-message=Oppf\u00f8ringer kan bare opprettes i oppf\u00f8ringsmapper, og dette er en {0}.
rm.action.transfer-non-editable=Overf\u00f8ringsmapper eller beholdermetadata kan ikke redigeres.
rm.action.node.frozen.error-message=Kan ikke utf\u00f8re handlingen {0} fordi noden er frossen eller har frosne underordnede elementer.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=U kunt geen onderdelen m
rm.action.create.transfer.child-error-message=U kunt geen onderdelen maken in overdrachtsmappen.
rm.action.create.record.folder.child-error-message=U kunt alleen archiefstukken maken in archiefmappen en dit was een {0}.
rm.action.transfer-non-editable=U kunt metagegevens in een overdrachtsmap of -container niet bewerken.
rm.action.node.frozen.error-message=Kan de actie {0} niet uitvoeren omdat de node geblokkeerd is of geblokkeerde onderliggende elementen heeft.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Nie mo\u017cna utworzy\u
rm.action.create.transfer.child-error-message=Nie mo\u017cna utworzy\u0107 pozycji w folderach przesy\u0142ania.
rm.action.create.record.folder.child-error-message=W folderach rekord\u00f3w mo\u017cna tworzy\u0107 tylko rekordy, a to by\u0142o {0}.
rm.action.transfer-non-editable=Nie mo\u017cna edytowa\u0107 folderu przesy\u0142ania ani metadanych kontenera.
rm.action.node.frozen.error-message=Nie mo\u017cna wykona\u0107 czynno\u015bci {0}, poniewa\u017c w\u0119ze\u0142 jest zablokowany lub ma zablokowane elementy podrz\u0119dne.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=N\u00e3o \u00e9 poss\u00
rm.action.create.transfer.child-error-message=N\u00e3o \u00e9 poss\u00edvel criar itens nas pastas de Transfer\u00eancia.
rm.action.create.record.folder.child-error-message=\u00c9 poss\u00edvel apenas criar documentos arquiv\u00edsticos em pastas de documentos arquiv\u00edsticos; esta foi {0}.
rm.action.transfer-non-editable=N\u00e3o \u00e9 poss\u00edvel editar os metadados das pastas de transfer\u00eancia ou cont\u00eainer.
rm.action.node.frozen.error-message=N\u00e3o \u00e9 poss\u00edvel executar a a\u00e7\u00e3o {0} porque o n\u00f3 est\u00e1 congelado ou tem filhos congelados.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=\u041d\u0435\u0432\u043e
rm.action.create.transfer.child-error-message=\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u043f\u0430\u043f\u043a\u0430\u0445 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438.
rm.action.create.record.folder.child-error-message=\u0417\u0430\u043f\u0438\u0441\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0430\u043f\u043a\u0430\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0430 \u044d\u0442\u043e {0}.
rm.action.transfer-non-editable=\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0438\u043b\u0438 \u043f\u0430\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438.
rm.action.node.frozen.error-message=\u041d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 {0}, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0443\u0437\u0435\u043b \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d \u0438\u043b\u0438 \u0438\u043c\u0435\u0435\u0442 \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=Du kan inte skapa objekt
rm.action.create.transfer.child-error-message=Du kan inte skapa objekt i \u00d6verf\u00f6ringsmappar.
rm.action.create.record.folder.child-error-message=Du kan endast skapa handlingar i handlingsmappar och detta var en {0}.
rm.action.transfer-non-editable=Du kan inte redigera \u00f6verf\u00f6ringsmappen eller beh\u00e5llarens metadata.
rm.action.node.frozen.error-message=Det gick inte att utf\u00f6ra \u00e5tg\u00e4rd {0} eftersom noden \u00e4r frusen eller har frysta underordnade.

View File

@@ -45,4 +45,4 @@ rm.action.create.transfer.container.child-error-message=\u60a8\u65e0\u6cd5\u5728
rm.action.create.transfer.child-error-message=\u60a8\u65e0\u6cd5\u5728 Transfer \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u9879\u76ee\u3002
rm.action.create.record.folder.child-error-message=\u60a8\u53ea\u80fd\u5728\u8bb0\u5f55\u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u8bb0\u5f55\uff0c\u4e14\u8fd9\u662f\u4e00\u4e2a {0}\u3002
rm.action.transfer-non-editable=\u60a8\u65e0\u6cd5\u7f16\u8f91\u4f20\u8f93\u6587\u4ef6\u5939\u6216\u5bb9\u5668\u5143\u6570\u636e\u3002
rm.action.node.frozen.error-message=\u65e0\u6cd5\u6267\u884c\u64cd\u4f5c{0}\uff0c\u56e0\u4e3a\u8282\u70b9\u5df2\u51bb\u7ed3\u6216\u51bb\u7ed3\u7684\u5b50\u8282\u70b9\u3002

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<properties>

View File

@@ -306,7 +306,7 @@ public class RMAfterInvocationProvider extends RMSecurityCommon
}
}
private boolean isUnfiltered(NodeRef nodeRef)
protected boolean isUnfiltered(NodeRef nodeRef)
{
return !nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT);

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<build>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<dependencies>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<properties>

View File

@@ -9,6 +9,6 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
</project>

View File

@@ -1,6 +1,6 @@
# Fetch image based on Tomcat 9.0, Java 11 and Centos 8
# More infos about this image: https://github.com/Alfresco/alfresco-docker-base-tomcat
FROM alfresco/alfresco-base-tomcat:9.0.45-java-11-centos-8
FROM alfresco/alfresco-base-tomcat:9.0.52-java-11-centos-7
# Set default docker_context.
ARG resource_path=target
@@ -65,12 +65,12 @@ RUN sed -i -e "s_log4j.appender.File.File\=alfresco.log_log4j.appender.File.File
# fontconfig is required by Activiti worflow diagram generator
# installing pinned dependencies as well
RUN yum install -y fontconfig-2.13.1-3.el8 \
dejavu-fonts-common-2.35-7.el8 \
fontpackages-filesystem-1.44-22.el8 \
freetype-2.9.1-4.el8_3.1 \
libpng-1.6.34-5.el8 \
dejavu-sans-fonts-2.35-7.el8 && \
RUN yum install -y fontconfig-2.13.0-4.3.el7 \
dejavu-fonts-common-2.33-6.el7 \
fontpackages-filesystem-1.44-8.el7 \
freetype-2.8-14.el7_9.1 \
libpng-1.5.13-8.el7 \
dejavu-sans-fonts-2.33-6.el7 && \
yum clean all
# The standard configuration is to have all Tomcat files owned by root with group GROUPNAME and whilst owner has read/write privileges,

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<modules>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<developers>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<properties>

14
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -24,7 +24,7 @@
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>1</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.revision>1</acs.version.revision>
<acs.version.label />
<amp.min.version>${acs.version.major}.0.0</amp.min.version>
@@ -61,13 +61,13 @@
<dependency.jackson-databind.version>2.12.4</dependency.jackson-databind.version>
<dependency.cxf.version>3.4.4</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.22</dependency.webscripts.version>
<dependency.webscripts.version>8.25</dependency.webscripts.version>
<dependency.bouncycastle.version>1.69</dependency.bouncycastle.version>
<dependency.mockito-core.version>3.11.2</dependency.mockito-core.version>
<dependency.mockito-all.version>1.10.19</dependency.mockito-all.version>
<dependency.org-json.version>20210307</dependency.org-json.version>
<dependency.commons-dbcp.version>1.4-DBCP330</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.8.0</dependency.commons-io.version>
<dependency.commons-io.version>2.11.0</dependency.commons-io.version>
<dependency.gson.version>2.8.5</dependency.gson.version>
<dependency.httpclient.version>4.5.13</dependency.httpclient.version>
<dependency.httpcore.version>4.4.14</dependency.httpcore.version>
@@ -105,7 +105,7 @@
<alfresco.googledrive.version>3.2.1.3</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.0.1</alfresco.aos-module.version>
<alfresco.api-explorer.version>7.1.0-A1</alfresco.api-explorer.version>
<alfresco.api-explorer.version>7.1.0.1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
<dependency.postgresql.version>42.2.20</dependency.postgresql.version>
@@ -114,7 +114,7 @@
<dependency.mariadb.version>2.7.2</dependency.mariadb.version>
<dependency.tas-utility.version>3.0.45</dependency.tas-utility.version>
<dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.63</dependency.tas-restapi.version>
<dependency.tas-restapi.version>1.64</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.30</dependency.tas-cmis.version>
<dependency.tas-email.version>1.8</dependency.tas-email.version>
<dependency.tas-webdav.version>1.6</dependency.tas-webdav.version>
@@ -142,7 +142,7 @@
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>11.128</tag>
<tag>12.7</tag>
</scm>
<distributionManagement>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<dependencies>

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -30,6 +30,7 @@ import java.net.SocketException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import javax.servlet.http.HttpServletResponse;
@@ -355,7 +356,10 @@ public class RepositoryContainer extends AbstractRuntimeContainer
return;
}
if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
// if the required authentication is not equal to guest, then it should be one of the following:
// user | sysadmin | admin (the 'none' authentication is handled above)
// in this case the guest user should not be able to execute those scripts.
if (required != RequiredAuthentication.guest && isGuest)
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
@@ -383,28 +387,9 @@ public class RepositoryContainer extends AbstractRuntimeContainer
{
return false;
}
// The user will now have been authenticated, based on HTTP Auth, Ticket etc
// The user will now have been authenticated, based on HTTP Auth, Ticket, etc.
// Check that the user they authenticated as has appropriate access to the script
// Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin)
{
final String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
final String runAsUser = AuthenticationUtil.getRunAsUser();
if ( (authenticatedUser == null) ||
(authenticatedUser.equals(runAsUser) && authorityService.hasGuestAuthority()) ||
(!authenticatedUser.equals(runAsUser) && authorityService.isGuestAuthority(authenticatedUser)) )
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
}
// Check to see if they're admin or system on an Admin only script
if (required == RequiredAuthentication.admin && !(authorityService.hasAdminAuthority() || AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getSystemUserName())))
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
}
checkScriptAccess(required, desc.getId());
if (debug)
{
@@ -424,7 +409,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
// Execute Web Script if authentication passed
// The Web Script has its own txn management with potential runAs() user
transactionedExecuteAs(script, scriptReq, scriptRes);
transactionedExecuteAs(script, scriptReq, scriptRes, required);
}
finally
{
@@ -441,6 +426,65 @@ public class RepositoryContainer extends AbstractRuntimeContainer
}
}
private boolean isSystemUser()
{
return Objects.equals(AuthenticationUtil.getFullyAuthenticatedUser(), AuthenticationUtil.getSystemUserName());
}
private boolean isSysAdminUser()
{
return authorityService.hasSysAdminAuthority();
}
private boolean isAdmin()
{
return authorityService.hasAdminAuthority();
}
public final boolean isAdminOrSystemUser()
{
return isAdmin() || isSystemUser();
}
/**
* Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
*/
private void checkGuestAccess(RequiredAuthentication required, String scriptDescriptorId)
{
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin
|| required == RequiredAuthentication.sysadmin)
{
final String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
final String runAsUser = AuthenticationUtil.getRunAsUser();
if ((authenticatedUser == null) || (authenticatedUser.equals(runAsUser)
&& authorityService.hasGuestAuthority()) || (!authenticatedUser.equals(runAsUser)
&& authorityService.isGuestAuthority(authenticatedUser)))
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + scriptDescriptorId
+ " requires user authentication; however, a guest has attempted access.");
}
}
}
private void checkScriptAccess(RequiredAuthentication required, String scriptDescriptorId)
{
// first, check guest access
checkGuestAccess(required, scriptDescriptorId);
// Check to see if the user is sysAdmin, admin or system on a sysadmin scripts
if (required == RequiredAuthentication.sysadmin && !(isSysAdminUser() || isAdminOrSystemUser()))
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + scriptDescriptorId
+ " requires system-admin authentication; however, a non-system-admin has attempted access.");
}
else if (required == RequiredAuthentication.admin && !isAdminOrSystemUser())
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + scriptDescriptorId
+ " requires admin authentication; however, a non-admin has attempted access.");
}
}
/**
* Execute script within required level of transaction
*
@@ -626,6 +670,35 @@ public class RepositoryContainer extends AbstractRuntimeContainer
}, runAs);
}
}
/**
* Execute script within required level of transaction as required effective user.
*
* @param script WebScript
* @param scriptReq WebScriptRequest
* @param scriptRes WebScriptResponse
* @param requiredAuthentication Required authentication
* @throws IOException
*/
private void transactionedExecuteAs(final WebScript script, final WebScriptRequest scriptReq,
final WebScriptResponse scriptRes, RequiredAuthentication requiredAuthentication) throws IOException
{
// Execute as System if and only if, the current user is a member of System-Admin group, and he is not a super admin.
// E.g. if 'jdoe' is a member of ALFRESCO_SYSTEM_ADMINISTRATORS group, then the work should be executed as System to satisfy the ACL checks.
// But, if the current user is Admin (i.e. super admin, which by default he is a member fo the ALFRESCO_SYSTEM_ADMINISTRATORS group)
// then don't wrap the work as RunAs, since he can do anything!
if (requiredAuthentication == RequiredAuthentication.sysadmin && isSysAdminUser() && !isAdmin())
{
AuthenticationUtil.runAs(() -> {
transactionedExecute(script, scriptReq, scriptRes);
return null;
}, AuthenticationUtil.SYSTEM_USER_NAME);
}
else
{
transactionedExecuteAs(script, scriptReq, scriptRes);
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#onApplicationEvent(org.springframework.context.ApplicationEvent)

View File

@@ -30,8 +30,19 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.function.Function;
import java.util.function.Supplier;
import com.google.common.primitives.Ints;
import org.alfresco.repo.bulkimport.BulkFilesystemImporter;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.NodeImporter;
import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
@@ -39,8 +50,12 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* contains common fields and methods for the import web scripts.
@@ -60,10 +75,10 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
// Web scripts parameters (common)
protected static final String PARAMETER_REPLACE_EXISTING = "replaceExisting";
protected static final String PARAMETER_EXISTING_FILE_MODE = "existingFileMode";
protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "replaceExisting";
protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "true";
protected static final String PARAMETER_SOURCE_DIRECTORY = "sourceDirectory";
protected static final String PARAMETER_DISABLE_RULES = "disableRules";
protected static final String PARAMETER_VALUE_DISABLE_RULES = "disableRules";
protected static final String PARAMETER_VALUE_DISABLE_RULES = "true";
protected static final String IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY = "importInProgress";
protected static final String IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY ="bfsit.error.importAlreadyInProgress";
@@ -75,7 +90,7 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
protected Repository repository;
protected volatile boolean importInProgress;
protected NodeRef getTargetNodeRef(String targetNodeRefStr, String targetPath) throws FileNotFoundException
{
NodeRef targetNodeRef;
@@ -219,4 +234,198 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
this.repository = repository;
}
protected class MultithreadedImportWebScriptLogic
{
private final MultiThreadedBulkFilesystemImporter bulkImporter;
private final Supplier<NodeImporter> nodeImporterFactory;
private final WebScriptRequest request;
private final Status status;
private final Cache cache;
public MultithreadedImportWebScriptLogic(MultiThreadedBulkFilesystemImporter bulkImporter, Supplier<NodeImporter> nodeImporterFactory, WebScriptRequest request, Status status, Cache cache)
{
this.bulkImporter = Objects.requireNonNull(bulkImporter);
this.nodeImporterFactory = Objects.requireNonNull(nodeImporterFactory);
this.request = Objects.requireNonNull(request);
this.status = Objects.requireNonNull(status);
this.cache = Objects.requireNonNull(cache);
}
public Map<String, Object> executeImport()
{
Map<String, Object> model = new HashMap<>();
cache.setNeverCache(true);
String targetPath = null;
try
{
targetPath = request.getParameter(PARAMETER_TARGET_PATH);
if (isRunning())
{
model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY));
return model;
}
final BulkImportParameters bulkImportParameters = getBulkImportParameters();
final NodeImporter nodeImporter = nodeImporterFactory.get();
bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter);
waitForImportToBegin();
// redirect to the status Web Script
status.setCode(Status.STATUS_MOVED_TEMPORARILY);
status.setRedirect(true);
status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS);
}
catch (WebScriptException | IllegalArgumentException e)
{
status.setCode(Status.STATUS_BAD_REQUEST, e.getMessage());
status.setRedirect(true);
}
catch (FileNotFoundException fnfe)
{
status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !");
status.setRedirect(true);
}
catch (Throwable t)
{
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t);
}
return model;
}
private void waitForImportToBegin() throws InterruptedException
{
// ACE-3047 fix, since bulk import is started asynchronously there is a chance that client
// will get into the status page before import is actually started.
// In this case wrong information (for previous import) will be displayed.
// So lets ensure that import started before redirecting client to status page.
int i = 0;
while (!bulkImporter.getStatus().inProgress() && i < 10)
{
Thread.sleep(100);
i++;
}
}
private BulkImportParameters getBulkImportParameters() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = new BulkImportParametersExtractor(request::getParameter,
AbstractBulkFileSystemImportWebScript.this::getTargetNodeRef,
bulkImporter.getDefaultBatchSize(),
bulkImporter.getDefaultNumThreads());
return extractor.extract();
}
private boolean isRunning()
{
return bulkImporter.getStatus().inProgress();
}
}
protected static class BulkImportParametersExtractor
{
private final Function<String, String> paramsProvider;
private final NodeRefCreator nodeRefCreator;
private final int defaultBatchSize;
private final int defaultNumThreads;
public BulkImportParametersExtractor(final Function<String, String> paramsProvider, final NodeRefCreator nodeRefCreator,
final int defaultBatchSize, final int defaultNumThreads)
{
this.paramsProvider = Objects.requireNonNull(paramsProvider);
this.nodeRefCreator = Objects.requireNonNull(nodeRefCreator);
this.defaultBatchSize = defaultBatchSize;
this.defaultNumThreads = defaultNumThreads;
}
public BulkImportParameters extract() throws FileNotFoundException
{
BulkImportParameters result = new BulkImportParameters();
result.setTarget(getTargetNodeRef());
setExistingFileMode(result);
result.setNumThreads(getOptionalPositiveInteger(PARAMETER_NUM_THREADS).orElse(defaultNumThreads));
result.setBatchSize(getOptionalPositiveInteger(PARAMETER_BATCH_SIZE).orElse(defaultBatchSize));
setDisableRules(result);
return result;
}
private void setExistingFileMode(BulkImportParameters params)
{
String replaceExistingStr = getParamStringValue(PARAMETER_REPLACE_EXISTING);
String existingFileModeStr = getParamStringValue(PARAMETER_EXISTING_FILE_MODE);
if (!isNullOrEmpty(replaceExistingStr) && !isNullOrEmpty(existingFileModeStr))
{
// Check that we haven't had both the deprecated and new (existingFileMode)
// parameters supplied.
throw new IllegalStateException(
String.format("Only one of these parameters may be used, not both: %s, %s",
PARAMETER_REPLACE_EXISTING,
PARAMETER_EXISTING_FILE_MODE));
}
if (!isNullOrEmpty(existingFileModeStr))
{
params.setExistingFileMode(BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr));
}
else
{
params.setReplaceExisting(PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr));
}
}
private void setDisableRules(final BulkImportParameters params)
{
final String disableRulesStr = getParamStringValue(PARAMETER_DISABLE_RULES);
params.setDisableRulesService(!isNullOrEmpty(disableRulesStr) && PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr));
}
private NodeRef getTargetNodeRef() throws FileNotFoundException
{
String targetNodeRefStr = getParamStringValue(PARAMETER_TARGET_NODEREF);
String targetPath = getParamStringValue(PARAMETER_TARGET_PATH);
return nodeRefCreator.fromNodeRefAndPath(targetNodeRefStr, targetPath);
}
private OptionalInt getOptionalPositiveInteger(final String paramName)
{
final String strValue = getParamStringValue(paramName);
if (isNullOrEmpty(strValue))
{
return OptionalInt.empty();
}
final Integer asInt = Ints.tryParse(strValue);
if (asInt == null || asInt < 1)
{
throw new WebScriptException("Error: parameter '" + paramName + "' must be an integer > 0.");
}
return OptionalInt.of(asInt);
}
private String getParamStringValue(String paramName)
{
Objects.requireNonNull(paramName);
return paramsProvider.apply(paramName);
}
private boolean isNullOrEmpty(String str)
{
return str == null || str.trim().length() == 0;
}
@FunctionalInterface
protected interface NodeRefCreator
{
NodeRef fromNodeRefAndPath(String nodeRef, String path) throws FileNotFoundException;
}
}
}

View File

@@ -27,17 +27,12 @@
package org.alfresco.repo.web.scripts.bulkimport.copy;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.NodeImporter;
import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter;
import org.alfresco.repo.bulkimport.impl.StreamingNodeImporterFactory;
import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
@@ -69,170 +64,22 @@ public class BulkFilesystemImportWebScript extends AbstractBulkFileSystemImportW
@Override
protected Map<String, Object> executeImpl(final WebScriptRequest request, final Status status, final Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
String targetNodeRefStr = null;
String targetPath = null;
String sourceDirectoryStr = null;
@Deprecated String replaceExistingStr = null;
String existingFileModeStr = null;
String batchSizeStr = null;
String numThreadsStr = null;
String disableRulesStr = null;
final MultithreadedImportWebScriptLogic importLogic = new MultithreadedImportWebScriptLogic(bulkImporter,
() -> createNodeImporter(request), request, status, cache);
return importLogic.executeImport();
}
cache.setNeverCache(true);
try
private NodeImporter createNodeImporter(WebScriptRequest request)
{
final String sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY);
if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0)
{
if(!bulkImporter.getStatus().inProgress())
{
NodeRef targetNodeRef = null;
File sourceDirectory = null;
boolean replaceExisting = false;
BulkImportParameters.ExistingFileMode existingFileMode = null;
int batchSize = bulkImporter.getDefaultBatchSize();
int numThreads = bulkImporter.getDefaultNumThreads();
boolean disableRules = false;
// Retrieve, validate and convert parameters
targetNodeRefStr = request.getParameter(PARAMETER_TARGET_NODEREF);
targetPath = request.getParameter(PARAMETER_TARGET_PATH);
sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY);
replaceExistingStr = request.getParameter(PARAMETER_REPLACE_EXISTING);
existingFileModeStr = request.getParameter(PARAMETER_EXISTING_FILE_MODE);
batchSizeStr = request.getParameter(PARAMETER_BATCH_SIZE);
numThreadsStr = request.getParameter(PARAMETER_NUM_THREADS);
disableRulesStr = request.getParameter(PARAMETER_DISABLE_RULES);
targetNodeRef = getTargetNodeRef(targetNodeRefStr, targetPath);
if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0)
{
throw new RuntimeException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided.");
}
sourceDirectory = new File(sourceDirectoryStr.trim());
if (replaceExistingStr != null && existingFileModeStr != null)
{
// Check that we haven't had both the deprecated and new (existingFileMode)
// parameters supplied.
throw new IllegalStateException(
String.format("Only one of these parameters may be used, not both: %s, %s",
PARAMETER_REPLACE_EXISTING,
PARAMETER_EXISTING_FILE_MODE));
}
if (replaceExistingStr != null && replaceExistingStr.trim().length() > 0)
{
replaceExisting = PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr);
}
if (existingFileModeStr != null && existingFileModeStr.trim().length() > 0)
{
existingFileMode = BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr);
}
if (disableRulesStr != null && disableRulesStr.trim().length() > 0)
{
disableRules = PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr);
}
// Initiate the import
NodeImporter nodeImporter = nodeImporterFactory.getNodeImporter(sourceDirectory);
BulkImportParameters bulkImportParameters = new BulkImportParameters();
if (numThreadsStr != null && numThreadsStr.trim().length() > 0)
{
try
{
numThreads = Integer.parseInt(numThreadsStr);
if(numThreads < 1)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0.");
}
bulkImportParameters.setNumThreads(numThreads);
}
catch(NumberFormatException e)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0.");
}
}
if (batchSizeStr != null && batchSizeStr.trim().length() > 0)
{
try
{
batchSize = Integer.parseInt(batchSizeStr);
if(batchSize < 1)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0.");
}
bulkImportParameters.setBatchSize(batchSize);
}
catch(NumberFormatException e)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0.");
}
}
if (existingFileMode != null)
{
bulkImportParameters.setExistingFileMode(existingFileMode);
}
else
{
// Fall back to the old/deprecated way.
bulkImportParameters.setReplaceExisting(replaceExisting);
}
bulkImportParameters.setTarget(targetNodeRef);
bulkImportParameters.setDisableRulesService(disableRules);
bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter);
// ACE-3047 fix, since bulk import is started asynchronously there is a chance that client
// will get into the status page before import is actually started.
// In this case wrong information (for previous import) will be displayed.
// So lets ensure that import started before redirecting client to status page.
int i = 0;
while (!bulkImporter.getStatus().inProgress() && i < 10)
{
Thread.sleep(100);
i++;
}
// redirect to the status Web Script
status.setCode(Status.STATUS_MOVED_TEMPORARILY);
status.setRedirect(true);
status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS);
}
else
{
model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY));
}
throw new WebScriptException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided.");
}
catch (WebScriptException wse)
{
status.setCode(Status.STATUS_BAD_REQUEST, wse.getMessage());
status.setRedirect(true);
}
catch (FileNotFoundException fnfe)
{
status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !");
status.setRedirect(true);
}
catch(IllegalArgumentException iae)
{
status.setCode(Status.STATUS_BAD_REQUEST,iae.getMessage());
status.setRedirect(true);
}
catch (Throwable t)
{
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t);
}
return model;
final File sourceDirectory = new File(sourceDirectoryStr.trim());
return nodeImporterFactory.getNodeImporter(sourceDirectory);
}
}

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.quickshare;
import java.util.HashMap;
@@ -31,10 +31,12 @@ import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.service.cmr.quickshare.InvalidSharedIdException;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
@@ -82,14 +84,15 @@ public class UnshareContentDelete extends AbstractQuickShareContent
try
{
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedBy))
TenantUtil.runAsSystemTenant(() ->
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Can't perform unshare action: " + sharedId);
}
quickShareService.unshareContent(sharedId);
checkIfCanDeleteSharedLink(sharedId);
quickShareService.unshareContent(sharedId);
return null;
}, networkTenantDomain);
Map<String, Object> model = new HashMap<>(1);
model.put("success", Boolean.TRUE);
@@ -106,4 +109,14 @@ public class UnshareContentDelete extends AbstractQuickShareContent
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: " + sharedId);
}
}
private void checkIfCanDeleteSharedLink(String sharedId) {
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedBy))
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Can't perform unshare action: " + sharedId);
}
}
}

View File

@@ -274,15 +274,15 @@ public class QuickShareLinksImpl implements QuickShareLinks, RecognizedParamsExt
try
{
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
String sharedByUserId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedByUserId))
TenantUtil.runAsSystemTenant(() ->
{
throw new PermissionDeniedException("Can't perform unshare action: " + sharedId);
}
quickShareService.unshareContent(sharedId);
checkIfCanDeleteSharedLink(sharedId);
quickShareService.unshareContent(sharedId);
return null;
}, networkTenantDomain);
}
catch (InvalidSharedIdException ex)
{
@@ -698,4 +698,14 @@ public class QuickShareLinksImpl implements QuickShareLinks, RecognizedParamsExt
throw new InvalidArgumentException("A valid recipientEmail must be specified.");
}
}
private void checkIfCanDeleteSharedLink(String sharedId) {
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
String sharedByUserId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedByUserId))
{
throw new PermissionDeniedException("Can't perform unshare action: " + sharedId);
}
}
}

View File

@@ -63,6 +63,7 @@ public class RestApiDirectUrlConfig extends AbstractDirectUrlConfig
logger.error("Disabling REST API direct access URLs due to configuration error: " + ex.getMessage());
setEnabled(false);
}
logger.info("REST API direct access URLs are " + (isEnabled() ? "enabled" : "disabled"));
}
/* Helper method to validate the REST API direct access url configuration settings */

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -35,6 +35,7 @@ import org.alfresco.repo.jscript.ScriptUtils;
import org.alfresco.repo.web.scripts.RepositoryContainer;
import org.alfresco.service.cmr.admin.RepoUsage;
import org.alfresco.service.cmr.repository.StoreRef;
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
import org.springframework.extensions.webscripts.WebScript;
/**
@@ -65,27 +66,61 @@ public class WebScriptUtils extends ScriptUtils
*/
public Object[] findWebScripts(String family)
{
List<Object> values = new ArrayList<Object>();
List<Object> values = new ArrayList<>();
for (WebScript webscript : this.repositoryContainer.getRegistry().getWebScripts())
{
if (family != null)
addScriptDescription(family, values, webscript);
}
return values.toArray(new Object[0]);
}
/**
* Searches for webscript components with the given family name accessible to the current user.
*
* @param family the family
*
* @return An array of webscripts that match the given family name accessible to the current user
*
* @since 7.1
*/
public Object[] findWebScriptsForCurrentUser(String family)
{
List<Object> values = new ArrayList<>();
final boolean isAdminOrSystemUser = repositoryContainer.isAdminOrSystemUser();
for (WebScript webscript : this.repositoryContainer.getRegistry().getWebScripts())
{
final RequiredAuthentication required = webscript.getDescription().getRequiredAuthentication();
// Ignore admin webscripts if the current user is not an Admin or System
if (RequiredAuthentication.admin == required && !isAdminOrSystemUser)
{
Set<String> familys = webscript.getDescription().getFamilys();
if (familys != null && familys.contains(family))
{
values.add(webscript.getDescription());
}
continue;
}
else
addScriptDescription(family, values, webscript);
}
return values.toArray(new Object[0]);
}
private void addScriptDescription(String family, List<Object> values, WebScript webscript)
{
if (family != null)
{
Set<String> families = webscript.getDescription().getFamilys();
if (families != null && families.contains(family))
{
values.add(webscript.getDescription());
}
}
return values.toArray(new Object[0]);
else
{
values.add(webscript.getDescription());
}
}
public String getHostAddress()
{
try

View File

@@ -1070,7 +1070,7 @@
<property name="enabled" value="${system.api.discovery.enabled}" />
<property name="thumbnailService" ref="ThumbnailService" />
<property name="restApiDirectUrlConfig" ref="restApiDirectUrlConfig" />
<property name="contentService" ref="ContentService" />
<property name="contentService" ref="contentService" />
</bean>
<bean id="org.alfresco.rest.api.probes.ProbeEntityResource.get" class="org.alfresco.rest.api.probes.ProbeEntityResource">

View File

@@ -40,7 +40,7 @@ var Admin = Admin || {};
var toolInfo = {};
// collect the tools required for the Admin Console
var tools = utils.findWebScripts("AdminConsole");
var tools = utils.findWebScriptsForCurrentUser("AdminConsole");
// process each tool and generate the data so that a label+link can
// be output by the component template for each tool required

View File

@@ -7,7 +7,7 @@
<!-- COMMUNITY ONLY -->
<family>AdminConsole:Edition:Community</family>
<format default="html">argument</format>
<authentication>admin</authentication>
<authentication>sysadmin</authentication>
<lifecycle>internal</lifecycle>
<transaction allow="readonly">required</transaction>
</webscript>
</webscript>

View File

@@ -5,7 +5,7 @@
<url>/admin/</url>
<family>AdminConsoleHelper</family>
<format default="html">argument</format>
<authentication>admin</authentication>
<authentication>sysadmin</authentication>
<lifecycle>internal</lifecycle>
<transaction allow="readonly">required</transaction>
</webscript>
</webscript>

View File

@@ -5,7 +5,7 @@
</description>
<url>/api/admin/jmxdump</url>
<family>AdminConsoleHelper</family>
<authentication>admin</authentication>
<authentication>sysadmin</authentication>
<transaction allow="readonly"/>
<lifecycle>internal</lifecycle>
</webscript>
</webscript>

View File

@@ -3,8 +3,8 @@
<description>Update and retrieve repository usage</description>
<url>/api/admin/usage</url>
<format default="json" />
<authentication>admin</authentication>
<authentication>sysadmin</authentication>
<transaction>required</transaction>
<family>Admin</family>
<lifecycle>internal</lifecycle>
</webscript>
</webscript>

View File

@@ -42,6 +42,7 @@ import org.junit.runners.Suite;
org.alfresco.rest.api.tests.TestPublicApiAtomPub10TCK.class,
org.alfresco.rest.api.tests.TestPublicApiAtomPub11TCK.class,
org.alfresco.rest.api.tests.TestPublicApiBrowser11TCK.class,
org.alfresco.repo.web.scripts.bulkimport.BulkImportParametersExtractorTest.class
})
public class AppContext01TestSuite
{

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -31,10 +31,12 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.dictionary.Facetable;
import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.AuthorityServiceImpl;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.admin.RepoUsage;
@@ -48,11 +50,18 @@ import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.i18n.MessageLookup;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.license.LicenseDescriptor;
import org.alfresco.service.namespace.QName;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.PropertyMap;
import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext;
@@ -74,29 +83,46 @@ import static org.mockito.Mockito.when;
@Category(OwnJVMTestsCategory.class)
public class AdminWebScriptTest extends BaseWebScriptTest
{
private ApplicationContext ctx;
private RepoAdminService repoAdminService;
private DescriptorService descriptorService;
private RepoAdminService repoAdminService;
private DescriptorService descriptorService;
private PersonService personService;
private MutableAuthenticationService authenticationService;
private String admin;
private String guest;
private String user1_sysAdmin;
private String user2;
@Override
protected void setUp() throws Exception
{
super.setUp();
ctx = getServer().getApplicationContext();
repoAdminService = (RepoAdminService) ctx.getBean("RepoAdminService");
descriptorService = (DescriptorService) ctx.getBean("DescriptorService");
ApplicationContext ctx = getServer().getApplicationContext();
repoAdminService = ctx.getBean("RepoAdminService", RepoAdminService.class);
descriptorService = ctx.getBean("DescriptorService", DescriptorService.class);
personService = ctx.getBean("PersonService", PersonService.class);
authenticationService = ctx.getBean("AuthenticationService", MutableAuthenticationService.class);
AuthorityService authorityService = ctx.getBean("AuthorityService", AuthorityService.class);
admin = AuthenticationUtil.getAdminUserName();
guest = AuthenticationUtil.getGuestUserName();
AuthenticationUtil.setFullyAuthenticatedUser(admin);
user1_sysAdmin = RandomStringUtils.randomAlphabetic(10);
String user1_password = RandomStringUtils.randomAlphabetic(10);
createUser(user1_sysAdmin, user1_password);
authorityService.addAuthority(AuthorityServiceImpl.GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY, user1_sysAdmin);
user2 = RandomStringUtils.randomAlphabetic(10);
String user2_password = RandomStringUtils.randomAlphabetic(10);
createUser(user2, user2_password);
}
@Override
protected void tearDown() throws Exception
{
super.tearDown();
AuthenticationUtil.clearCurrentSecurityContext();
}
public void testGetRestrictions() throws Exception
@@ -227,6 +253,129 @@ public class AdminWebScriptTest extends BaseWebScriptTest
assertTrue(property.getResidual());
}
public void testSysAdminAccess() throws Exception
{
AuthenticationUtil.clearCurrentSecurityContext();
String url = "/admin/admin-communitysummary";
TestWebScriptServer.GetRequest req = new TestWebScriptServer.GetRequest(url);
Response response = sendRequest(req, Status.STATUS_OK, user1_sysAdmin);
Document doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("System Summary"));
// Super Admin should still have access to all the scripts
response = sendRequest(req, Status.STATUS_OK, admin);
doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("System Summary"));
}
public void testSysAdminAccess_nodeBrowser() throws Exception
{
AuthenticationUtil.clearCurrentSecurityContext();
String nodeBrowserUrl = "/admin/admin-nodebrowser";
// test the get webscript of the node browser
TestWebScriptServer.GetRequest getReq = new TestWebScriptServer.GetRequest(nodeBrowserUrl);
// The node browser is only accessible to admins, not sysAdmins
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// test the post webscript of the node browser too
TestWebScriptServer.PostRequest postReq = new TestWebScriptServer.PostRequest(nodeBrowserUrl, "",
"multipart/form-data; boundary=----WebKitFormBoundaryjacWCXfJ3KjtRenA");
// The node browser is only accessible to admins, not sysAdmins
sendRequest(postReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// Normal user shouldn't have access either
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user2);
// Admin should have access to everything
Response response = sendRequest(getReq, Status.STATUS_OK, admin);
Document doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("Node Browser"));
}
public void testSysAdminAccess_repoConsole() throws Exception
{
String repoConsoleUrl = "/admin/admin-repoconsole";
// test the get webscript of the repo console
TestWebScriptServer.GetRequest getReq = new TestWebScriptServer.GetRequest(repoConsoleUrl);
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// test the post webscript of the repo console too
TestWebScriptServer.PostRequest postReq = new TestWebScriptServer.PostRequest(repoConsoleUrl, "",
"multipart/form-data; boundary=----WebKitFormBoundaryjacWCXfJ3KjtRenA");
sendRequest(postReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// Normal user shouldn't have access either
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user2);
// Admin should have access to everything
Response response = sendRequest(getReq, Status.STATUS_OK, admin);
Document doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("Model and Messages Console"));
}
public void testSysAdminAccess_tenantConsole() throws Exception
{
String tenantConsoleUrl = "/admin/admin-tenantconsole";
// test the get webscript of the tenant console
TestWebScriptServer.GetRequest getReq = new TestWebScriptServer.GetRequest(tenantConsoleUrl);
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// test the post webscript of the tenant console too
TestWebScriptServer.PostRequest postReq = new TestWebScriptServer.PostRequest(tenantConsoleUrl, "",
"multipart/form-data; boundary=----WebKitFormBoundaryjacWCXfJ3KjtRenA");
sendRequest(postReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// Normal user shouldn't have access either
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user2);
// Admin should have access to everything
Response response = sendRequest(getReq, Status.STATUS_OK, admin);
Document doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("Tenant Admin Console"));
}
public void testSysAdminAccess_workflowConsole() throws Exception
{
String workflowConsoleUrl = "/admin/admin-workflowconsole";
// test the get webscript of the workflow console
TestWebScriptServer.GetRequest getReq = new TestWebScriptServer.GetRequest(workflowConsoleUrl);
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// test the post webscript of the workflow console too
TestWebScriptServer.PostRequest postReq = new TestWebScriptServer.PostRequest(workflowConsoleUrl, "",
"multipart/form-data; boundary=----WebKitFormBoundaryjacWCXfJ3KjtRenA");
sendRequest(postReq, Status.STATUS_UNAUTHORIZED, user1_sysAdmin);
// Normal user shouldn't have access either
sendRequest(getReq, Status.STATUS_UNAUTHORIZED, user2);
// Admin should have access to everything
Response response = sendRequest(getReq, Status.STATUS_OK, admin);
Document doc = Jsoup.parse(response.getContentAsString());
assertNotNull(doc.title());
assertTrue(doc.title().contains("Workflow Admin Console"));
}
public void testNonSysAdminAccess() throws Exception
{
AuthenticationUtil.clearCurrentSecurityContext();
String url = "/admin/admin-communitysummary";
TestWebScriptServer.GetRequest req = new TestWebScriptServer.GetRequest(url);
sendRequest(req, Status.STATUS_UNAUTHORIZED, user2);
}
private class SimplePropertyDefinition implements PropertyDefinition
{
private boolean isAspect;
@@ -350,4 +499,19 @@ public class AdminWebScriptTest extends BaseWebScriptTest
return null;
}
}
private void createUser(String username, String password)
{
if (!personService.personExists(username))
{
this.authenticationService.createAuthentication(username, password.toCharArray());
PropertyMap personProps = new PropertyMap();
personProps.put(ContentModel.PROP_USERNAME, username);
personProps.put(ContentModel.PROP_FIRSTNAME, "testFirstName");
personProps.put(ContentModel.PROP_LASTNAME, "testLastName");
personProps.put(ContentModel.PROP_EMAIL, username + "@email.com");
this.personService.createPerson(personProps);
}
}
}

View File

@@ -0,0 +1,252 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.bulkimport;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_BATCH_SIZE;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_DISABLE_RULES;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_NUM_THREADS;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_TARGET_NODEREF;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Map;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.BulkImportParameters.ExistingFileMode;
import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.BulkImportParametersExtractor;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.junit.Test;
import org.springframework.extensions.webscripts.WebScriptException;
public class BulkImportParametersExtractorTest
{
private static final String TEST_NODE_REF = "workspace://SpacesStore/this-is-just-a-test-ref";
private static final String TEST_MISSING_NODE_REF = "workspace://SpacesStore/this-is-just-a-not-existing-test-ref";
private static final Integer DEFAULT_BATCH_SIZE = 1234;
private static final Integer DEFAULT_NUMBER_OF_THREADS = 4321;
@Test
public void shouldExtractTargetRef() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF));
final BulkImportParameters params = extractor.extract();
assertNotNull(params);
assertNotNull(params.getTarget());
assertEquals(TEST_NODE_REF, params.getTarget().toString());
}
@Test
public void shouldFallbackToDefaultValues() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF));
final BulkImportParameters params = extractor.extract();
assertEquals(DEFAULT_BATCH_SIZE, params.getBatchSize());
assertEquals(DEFAULT_NUMBER_OF_THREADS, params.getNumThreads());
assertFalse(params.isDisableRulesService());
assertEquals(ExistingFileMode.SKIP, params.getExistingFileMode());
assertNull(params.getLoggingInterval());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToTrue() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "true"
));
final BulkImportParameters params = extractor.extract();
assertTrue(params.isDisableRulesService());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToFalse() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "false"
));
final BulkImportParameters params = extractor.extract();
assertFalse(params.isDisableRulesService());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToNotBooleanValue() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "unknown"
));
final BulkImportParameters params = extractor.extract();
assertFalse(params.isDisableRulesService());
}
@Test
public void shouldPropagateFileNotFoundExceptionWhenTargetIsNotFound()
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_MISSING_NODE_REF));
assertThrows(FileNotFoundException.class, extractor::extract);
}
@Test
public void shouldExtractValidBatchSize() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "1"));
final BulkImportParameters params = extractor.extract();
assertEquals(Integer.valueOf(1), params.getBatchSize());
}
@Test
public void shouldFailWithWebScriptExceptionWhenInvalidBatchSizeIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "not-a-number"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldFailWithWebScriptExceptionWhenNegativeBatchSizeIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "-1"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldExtractValidNumberOfThreads() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "1"));
final BulkImportParameters params = extractor.extract();
assertEquals(Integer.valueOf(1), params.getNumThreads());
}
@Test
public void shouldFailWithWebScriptExceptionWhenInvalidNumberOfThreadsIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "not-a-number"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldFailWithWebScriptExceptionWhenNegativeNumberOfThreadsIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "-1"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS));
return;
}
fail("Expected exception to be thrown.");
}
private BulkImportParametersExtractor givenExtractor(Map<String, String> params)
{
return new BulkImportParametersExtractor(params::get, this::testRefCreator, DEFAULT_BATCH_SIZE, DEFAULT_NUMBER_OF_THREADS);
}
private NodeRef testRefCreator(String nodeRef, String path) throws FileNotFoundException
{
if (TEST_MISSING_NODE_REF.equals(nodeRef))
{
throw new FileNotFoundException(new NodeRef(nodeRef));
}
return new NodeRef(nodeRef);
}
}

View File

@@ -78,8 +78,6 @@ public class DeletedNodesTest extends AbstractSingleNetworkSiteTest
protected static final String URL_DELETED_NODES = "deleted-nodes";
private static final String URL_RENDITIONS = "renditions";
private final static long DELAY_IN_MS = 500;
@Override
public void setup() throws Exception
@@ -732,6 +730,45 @@ public class DeletedNodesTest extends AbstractSingleNetworkSiteTest
HttpResponse dauResponse = post(getRequestArchivedContentDirectUrl(contentNodeId), null, null, null, null, 501);
}
@Test
public void testRequestArchivedRenditionDirectUrl() throws Exception
{
setRequestContext(user1);
// Create a folder within the site document's library
Date now = new Date();
String folder1 = "folder" + now.getTime() + "_1";
Folder createdFolder = createFolder(tDocLibNodeId, folder1, null);
assertNotNull(createdFolder);
String f1Id = createdFolder.getId();
// Create multipart request using an existing file
String fileName = "quick.pdf";
File file = getResourceFile(fileName);
MultiPartBuilder multiPartBuilder = MultiPartBuilder.create().setFileData(new MultiPartBuilder.FileData(fileName, file));
MultiPartBuilder.MultiPartRequest reqBody = multiPartBuilder.build();
// Upload quick.pdf file into 'folder'
HttpResponse response = post(getNodeChildrenUrl(f1Id), reqBody.getBody(), null, reqBody.getContentType(), 201);
Document document = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class);
String contentNodeId = document.getId();
Rendition rendition = createAndGetRendition(contentNodeId, "doclib");
assertNotNull(rendition);
String renditionID = rendition.getId();
assertEquals(Rendition.RenditionStatus.CREATED, rendition.getStatus());
deleteNode(contentNodeId);
HttpResponse dauResponse = post(getRequestArchivedRenditonContentDirectUrl(contentNodeId, renditionID), null, null, null, null, 501);
}
private String addToDocumentLibrary(String name, String nodeType, String userId) throws Exception
{
String parentId = getSiteContainerNodeId(Nodes.PATH_MY, "documentLibrary");
return createNode(parentId, name, nodeType, null).getId();
}
private String getDeletedNodeRenditionsUrl(String nodeId)
{
return URL_DELETED_NODES + "/" + nodeId + "/" + URL_RENDITIONS;

View File

@@ -224,6 +224,11 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return URL_DELETED_NODES + "/" + nodeId + "/" + REQUEST_DIRECT_ACCESS_URL;
}
protected String getRequestArchivedRenditonContentDirectUrl(String nodeId, String renditionID)
{
return URL_DELETED_NODES + "/" + nodeId + "/" + URL_RENDITIONS + "/" + renditionID + "/" + REQUEST_DIRECT_ACCESS_URL;
}
/**
* The api scope. either public or private
*

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.128</version>
<version>12.7</version>
</parent>
<dependencies>

View File

@@ -73,6 +73,7 @@ public class ContentStoreDirectUrlConfig extends AbstractDirectUrlConfig
logger.error("Disabling content store direct access URLs due to configuration error: " + ex.getMessage());
setEnabled(false);
}
logger.info("Content store direct access URLs are " + (isEnabled() ? "enabled" : "disabled"));
}
/* Helper method to validate the content direct access url configuration settings */

View File

@@ -96,6 +96,7 @@ public class SystemWideDirectUrlConfig implements DirectUrlConfig
logger.error("Disabling system-wide direct access URLs due to configuration error: " + ex.getMessage());
setEnabled(false);
}
logger.info("System-wide direct access URLs are " + (isEnabled() ? "enabled" : "disabled"));
}
/* Helper method to validate the system-wide direct access url configuration settings */

View File

@@ -415,12 +415,13 @@ implements TenantDeployer, DictionaryListener, /*TenantDictionaryListener, */Mes
for (NodeRef messageResource : nodeRefs)
{
String resourceName = (String) nodeService.getProperty(messageResource, ContentModel.PROP_NAME);
String bundleBaseName = messageService.getBaseBundleName(resourceName);
String messageResourcePath = nodeService.getPath(messageResource).toPrefixString(namespaceService);
String bundleBasePrefixedName = messageResourcePath.substring(messageResourcePath.lastIndexOf("/"));
String bundleBaseName = messageService.getBaseBundleName(bundleBasePrefixedName);
if (!resourceBundleBaseNames.contains(bundleBaseName))
{
messageService.registerResourceBundle(storeRef.toString() + repositoryLocation.getPath() + bundleBaseName);
resourceBundleBaseNames.add(bundleBaseName);
}
}

View File

@@ -1,30 +1,33 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -46,8 +49,6 @@ import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.OwnableService;
@@ -59,6 +60,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* @author andyh
*/
@@ -395,61 +397,53 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
{
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
}
else if (StoreRef.class.isAssignableFrom(params[cad.parameter[0]]))
if (List.class.isAssignableFrom(params[cad.parameter[0]]))
{
StoreRef storeRef = getArgument(invocation, cad.parameter[0]);
if (storeRef != null)
List<?> listArgument = getArgument(invocation, cad.parameter[0]);
if (listArgument != null)
{
if (log.isDebugEnabled())
NodeRef listNodeRef;
Integer accessAbstainOrDeny = null;
for (Object listElement : listArgument)
{
log.debug("\tPermission test against the store - using permissions on the root node");
}
if (nodeService.exists(storeRef))
{
testNodeRef = nodeService.getRootNode(storeRef);
}
}
}
else if (NodeRef.class.isAssignableFrom(params[cad.parameter[0]]))
{
testNodeRef = getArgument(invocation, cad.parameter[0]);
if (log.isDebugEnabled())
{
if (testNodeRef != null)
{
if (nodeService.exists(testNodeRef))
listNodeRef = getNodeRef(listElement, nodeService);
Integer currentValue = shouldAbstainOrDeny(cad.required, listNodeRef, abstainForClassQNames, nodeService, permissionService);
if (currentValue != null)
{
log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
if (currentValue == AccessDecisionVoter.ACCESS_DENIED)
{
return AccessDecisionVoter.ACCESS_DENIED;
}
else
{
accessAbstainOrDeny = currentValue;
}
}
else
{
log.debug("\tPermission test on non-existing node " +testNodeRef);
}
}
}
}
else if (ChildAssociationRef.class.isAssignableFrom(params[cad.parameter[0]]))
{
ChildAssociationRef testChildRef = getArgument(invocation, cad.parameter[0]);
if (testChildRef != null)
{
testNodeRef = testChildRef.getChildRef();
if (log.isDebugEnabled())
if (accessAbstainOrDeny != null)
{
if (nodeService.exists(testNodeRef))
{
log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
}
else
{
log.debug("\tPermission test on non-existing node " + testNodeRef);
}
return accessAbstainOrDeny;
}
if((hasMethodEntry == null) || (hasMethodEntry.booleanValue()))
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
else
{
return AccessDecisionVoter.ACCESS_DENIED;
}
}
}
else
{
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
Object testObject = getArgument(invocation, cad.parameter[0]);
//If the execution reaches here, then testNodeRef is always null
testNodeRef = getNodeRef(testObject, nodeService);
}
}
else if (cad.typeString.equals(ACL_ITEM))
@@ -584,44 +578,10 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
}
}
if (testNodeRef != null)
Integer accessAbstainOrDeny = shouldAbstainOrDeny(cad.required, testNodeRef, abstainForClassQNames, nodeService, permissionService);
if (accessAbstainOrDeny != null)
{
// now we know the node - we can abstain for certain types and aspects (eg. RM)
if(abstainForClassQNames.size() > 0)
{
// check node exists
if (nodeService.exists(testNodeRef))
{
QName typeQName = nodeService.getType(testNodeRef);
if(abstainForClassQNames.contains(typeQName))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
Set<QName> aspectQNames = nodeService.getAspects(testNodeRef);
for(QName abstain : abstainForClassQNames)
{
if(aspectQNames.contains(abstain))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
}
}
}
if (log.isDebugEnabled())
{
log.debug("\t\tNode ref is not null");
}
if (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)
{
if (log.isDebugEnabled())
{
log.debug("\t\tPermission is denied");
Thread.dumpStack();
}
return AccessDecisionVoter.ACCESS_DENIED;
}
return accessAbstainOrDeny;
}
}

View File

@@ -0,0 +1,175 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import java.util.Set;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods extracted from AclEntryVoter
*
* @author Lev Belava
*/
final class ACLEntryVoterUtils
{
private static final Logger LOG = LoggerFactory.getLogger(ACLEntryVoterUtils.class);
private ACLEntryVoterUtils()
{
}
/**
* Gets NodeRef for testObject based on inferred type
*
* @param testObject Tested object to work on
* @param nodeService Node service to perform checks on refs
* @return NodeRef for testObject or null if (testObject is null or StoreRef from testObject does not exist in the provided NodeService)
* @throws ACLEntryVoterException if testObject is not null and not one of a NodeRef or ChildAssociationRef types
*/
static NodeRef getNodeRef(Object testObject, NodeService nodeService)
{
if (testObject == null)
{
return null;
}
if (StoreRef.class.isAssignableFrom(testObject.getClass()))
{
LOG.debug("Permission test against the store - using permissions on the root node");
StoreRef storeRef = (StoreRef) testObject;
if (nodeService.exists(storeRef))
{
return nodeService.getRootNode(storeRef);
}
else
{
LOG.debug("StoreRef does not exist");
return null;
}
}
if (NodeRef.class.isAssignableFrom(testObject.getClass()))
{
NodeRef result = (NodeRef) testObject;
if (LOG.isDebugEnabled())
{
if (nodeService.exists(result))
{
LOG.debug("Permission test on node {}", nodeService.getPath(result));
}
else
{
LOG.debug("Permission test on non-existing node {}", result);
}
}
return result;
}
if (ChildAssociationRef.class.isAssignableFrom(testObject.getClass()))
{
ChildAssociationRef testChildRef = (ChildAssociationRef) testObject;
NodeRef result = testChildRef.getChildRef();
if (LOG.isDebugEnabled())
{
if (nodeService.exists(result))
{
LOG.debug("Permission test on node {}", nodeService.getPath(result));
}
else
{
LOG.debug("Permission test on non-existing node {}", result);
}
}
return result;
}
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
}
/**
* Checks if tested NodeRef instance is abstained or denied based on set of QNames to abstain and
*
* @param requiredPermissionReference Required permissions
* @param testNodeRef NodeRef to be verified
* @param abstainForClassQNames Set of QNames to abstain
* @param nodeService Node service to perform checks on tested NodeRef
* @param permissionService Permission service to check for required permissions
* @return null if testNodeRef is not abstained or denied, otherwise returns appropriate status.
*/
static Integer shouldAbstainOrDeny(SimplePermissionReference requiredPermissionReference, NodeRef testNodeRef, Set<QName> abstainForClassQNames,
NodeService nodeService, PermissionService permissionService)
{
if (testNodeRef == null)
{
return null;
}
LOG.debug("Node ref is not null");
if (abstainForClassQNames.size() > 0 && nodeService.exists(testNodeRef))
{
if (abstainForClassQNames.contains(nodeService.getType(testNodeRef)))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
Set<QName> testNodeRefAspects = nodeService.getAspects(testNodeRef);
for (QName abstain : abstainForClassQNames)
{
if (testNodeRefAspects.contains(abstain))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
}
}
if (AccessStatus.DENIED == permissionService.hasPermission(testNodeRef, requiredPermissionReference.toString()))
{
if (LOG.isDebugEnabled())
{
LOG.debug("Permission is denied");
Thread.dumpStack();
}
return AccessDecisionVoter.ACCESS_DENIED;
}
return null;
}
}

View File

@@ -12,6 +12,7 @@ ALTER TABLE alf_transaction
DROP COLUMN IF EXISTS server_id;
DROP TABLE IF EXISTS alf_server;
DROP SEQUENCE IF EXISTS alf_server_seq;
--
-- Record script finish

View File

@@ -125,7 +125,7 @@ cm_contentmodel.aspect.cm_auditable.title=Kan overv\u00e5ges
cm_contentmodel.aspect.cm_auditable.description=Kan overv\u00e5ges
cm_contentmodel.property.cm_created.title=Oprettelsesdato
cm_contentmodel.property.cm_created.description=Oprettelsesdato
cm_contentmodel.property.cm_creator.title=Oprettet af
cm_contentmodel.property.cm_creator.title=Opretter
cm_contentmodel.property.cm_creator.description=Den person, der oprettede elementet
cm_contentmodel.property.cm_modified.title=\u00c6ndringsdato
cm_contentmodel.property.cm_modified.description=Tidspunkt for, hvorn\u00e5r elementet senest blev \u00e6ndret

View File

@@ -93,7 +93,7 @@ iptcxmp_iptcmodel.property.Iptc4xmpExt_DigitalSourcefileType.title=Originalfotos
iptcxmp_iptcmodel.property.Iptc4xmpExt_DigitalSourcefileType.description=Kildens digitale filtype.
iptcxmp_iptcmodel.property.Iptc4xmpExt_DigitalSourceType.title=Kildetype til dette foto
iptcxmp_iptcmodel.property.Iptc4xmpExt_DigitalSourceType.description=Kildetype til dette digitale billede
iptcxmp_iptcmodel.property.Iptc4xmpExt_Event.title=Event
iptcxmp_iptcmodel.property.Iptc4xmpExt_Event.title=H\u00e6ndelse
iptcxmp_iptcmodel.property.Iptc4xmpExt_Event.description=Navngiver eller beskriver den specifikke begivenhed indholdet relaterer til.
iptcxmp_iptcmodel.property.plus_ImageSupplierID.title=Billedes leverand\u00f8r-ID
iptcxmp_iptcmodel.property.plus_ImageSupplierID.description=Identificerer emnets den nyeste leverand\u00f8r, som ikke n\u00f8dvendigvis er ejer eller opretter.
@@ -125,7 +125,7 @@ iptcxmp_iptcmodel.property.plus_LicensorCity.title=By
iptcxmp_iptcmodel.property.plus_LicensorCity.description=By for en person eller virksomhed, der skal kontaktes for at f\u00e5 en licens til brug af emnet, eller som har licens p\u00e5 emnet.
iptcxmp_iptcmodel.property.plus_LicensorCountry.title=Land
iptcxmp_iptcmodel.property.plus_LicensorCountry.description=Land for en person eller virksomhed, der skal kontaktes for at f\u00e5 en licens til brug af emnet, eller som har licens p\u00e5 emnet.
iptcxmp_iptcmodel.property.plus_LicensorEmail.title=e-mail
iptcxmp_iptcmodel.property.plus_LicensorEmail.title=E-mailadresse
iptcxmp_iptcmodel.property.plus_LicensorEmail.description=E-mail for en person eller virksomhed, der skal kontaktes for at f\u00e5 en licens til brug af emnet, eller som har licens p\u00e5 emnet.
iptcxmp_iptcmodel.property.plus_LicensorExtendedAddress.title=Udviddet adresse
iptcxmp_iptcmodel.property.plus_LicensorExtendedAddress.description=Udvidet adresse for en person eller virksomhed, der skal kontaktes for at f\u00e5 en licens til brug af emnet, eller som har licens p\u00e5 emnet.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=Die folgenden Probleme werden behoben, sobald das lange Ausf\u00fchrungspatch ''{0}'' ausgef\u00fchrt wurde.
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=Los siguientes problemas se resolver\u00e1n una vez que se haya ejecutado el parche de larga duraci\u00f3n {0}
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=Les probl\u00e8mes suivants seront r\u00e9solus une fois la longue ex\u00e9cution du correctif {0} termin\u00e9e
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=I problemi seguenti verranno risolti al termine dell''esecuzione della patch di lunga durata {0}
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=\u9577\u6642\u9593\u30d1\u30b9{0}\u3092\u5b9f\u884c\u3059\u308b\u3068\u3001\u6b21\u306e\u554f\u984c\u304c\u89e3\u6c7a\u3055\u308c\u307e\u3059
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=F\u00f8lgende problemer vil bli l\u00f8st s\u00e5 snart den lengekj\u00f8rende oppdateringen {0} har blitt kj\u00f8rt
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=De volgende problemen worden opgelost zodra de langlopende patch {0} is uitgevoerd
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=Os seguintes problemas ser\u00e3o resolvidos ap\u00f3s o patch de longa execu\u00e7\u00e3o {0} ter sido executado
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0448\u0435\u043d\u044b \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f {0}
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -38,7 +38,7 @@ system.schema_comp.index_columns_validator=Number of columns in index doesn''t m
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
system.schema_comp.schema_version_validator=version must be at least ''{0}''
# Optional long running patch messages...
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
system.schema_comp.patch_run_suggestion=\u4e00\u65e6\u8fd0\u884c\u4e86\u957f\u65f6\u95f4\u8fd0\u884c\u7684\u4fee\u8865\u7a0b\u5e8f{0}\uff0c\u4ee5\u4e0b\u95ee\u9898\u5c06\u5f97\u5230\u89e3\u51b3
# Clustering
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
version.schema=15002
version.schema=15100
# Directory configuration

View File

@@ -209,6 +209,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.security.authentication.AuthorizationTest.class,
org.alfresco.repo.security.permissions.PermissionCheckedCollectionTest.class,
org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSetTest.class,
org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtilsTest.class,
org.alfresco.repo.security.authentication.ChainingAuthenticationServiceTest.class,
org.alfresco.repo.security.authentication.NameBasedUserNameGeneratorTest.class,
org.alfresco.repo.version.common.VersionImplTest.class,

View File

@@ -31,17 +31,18 @@ import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.NamespaceDAO;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -50,6 +51,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -67,6 +69,8 @@ import org.apache.commons.logging.LogFactory;
import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext;
import junit.framework.TestCase;
/**
* @see RepoAdminServiceImpl
*
@@ -88,6 +92,7 @@ public class RepoAdminServiceImplTest extends TestCase
private NamespaceService namespaceService;
private BehaviourFilter behaviourFilter;
private DictionaryDAO dictionaryDAO;
private MessageService messageService;
final String modelPrefix = "model-";
final static String MKR = "{MKR}";
@@ -140,6 +145,7 @@ public class RepoAdminServiceImplTest extends TestCase
namespaceService = (NamespaceService) ctx.getBean("NamespaceService");
behaviourFilter = (BehaviourFilter)ctx.getBean("policyBehaviourFilter");
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
messageService = (MessageService) ctx.getBean("MessageService");
DbNodeServiceImpl dbNodeService = (DbNodeServiceImpl)ctx.getBean("dbNodeService");
dbNodeService.setEnableTimestampPropagation(false);
@@ -865,8 +871,182 @@ public class RepoAdminServiceImplTest extends TestCase
}
}
}
//
// TODO - Test custom message management
//
// Test deploy bundle from classpath
public void testDeployMessageBundleFromClasspath() throws Exception
{
String bundleBaseName = "mycustommessages";
String resourceClasspath = "alfresco/extension/messages/" + bundleBaseName;
final String message_key = "mycustommessages.key1";
final String message_value_default = "This is a custom message";
final String message_value_fr = "Ceci est un message personnalis\\u00e9";
final String message_value_de = "Dies ist eine benutzerdefinierte Nachricht";
// Undeploy the bundle
if (repoAdminService.getMessageBundles().contains(bundleBaseName))
{
repoAdminService.undeployMessageBundle(bundleBaseName);
}
// Verify the custom bundle is registered
assertFalse("The custom bundle should not be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
// Depoly the message bundle
repoAdminService.deployMessageBundle(resourceClasspath);
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify the custom bundle is registered
assertTrue("The custom bundle should be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
// Verify we have the messages for each locale
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
assertMessageValue("Cannot retrieve default message value", message_value_default, message_key, Locale.getDefault());
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
// Test deploy a non existent bundle
try
{
repoAdminService.deployMessageBundle("alfresco/extension/messages/inexistentbundle");
fail("Bundle was not supposed to be deployed");
}
catch (Exception e)
{
// Expected to fail
}
}
// Test deploy bundle from repo and reload bundles
public void testDeployMessageBundleFromRepo() throws Exception
{
final String bundleBaseName = "repoBundle";
final String message_key = "repoBundle.key1";
final String message_value = "Value 1";
final String message_value_fr = "Value FR";
final String message_value_de = "Value DE";
final String message_value_new = "New Value 1";
// Set location
NodeRef rootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
List<NodeRef> nodeRefs = searchService.selectNodes(rootNodeRef, "/app:company_home/app:dictionary/app:messages", null,
namespaceService, false);
assertEquals(1, nodeRefs.size());
NodeRef messagesNodeRef = nodeRefs.get(0);
// Clear messages of this bundle if they exist and are registered
clearRepoBundles(messagesNodeRef);
assertEquals(0, repoAdminService.getMessageBundles().size());
// Create and upload the message files
NodeRef messageNode_default = createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, null,
message_value);
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.FRANCE.toString(), message_value_fr);
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.GERMANY.toString(),
message_value_de);
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify we have the messages for each locale
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
assertMessageValue("Cannot retrieve default message value", message_value, message_key, Locale.getDefault());
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
// Change the values
putContentInMessageNode(messageNode_default, message_key, message_value_new);
// Verify we still have the old value
assertMessageValue("Unexpected change of message value", message_value, message_key, Locale.getDefault());
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify new values
assertMessageValue("Change of message value not reflected", message_value_new, message_key, Locale.getDefault());
}
/**
* Create messages node
*/
private NodeRef createMessagesNodeWithSingleKey(NodeRef parentNode, String bundleName, String key, String locale,
String localeValue)
{
String msg_extension = ".properties";
String filename = bundleName + msg_extension;
String messageValue = localeValue;
if (locale != null)
{
filename = bundleName + "_" + locale + msg_extension;
}
// Create a model node
NodeRef messageNode = this.nodeService.createNode(
parentNode,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
ContentModel.TYPE_CONTENT,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
).getChildRef();
putContentInMessageNode(messageNode, key, messageValue);
return messageNode;
}
/**
* Write content of message node
*/
private void putContentInMessageNode(NodeRef nodeRef, String key, String value)
{
ContentWriter contentWriter = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
contentWriter.setEncoding("UTF-8");
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
String messagesString = key + "=" + value;
contentWriter.putContent(messagesString);
}
/**
* Clear Repo Bundle
*/
private void clearRepoBundles(NodeRef parentNode)
{
List<String> repoBundles = repoAdminService.getMessageBundles();
for (String repoBundle : repoBundles)
{
repoAdminService.undeployMessageBundle(repoBundle);
}
List<ChildAssociationRef> messageNodes = nodeService.getChildAssocs(parentNode);
for (ChildAssociationRef messageChildRef : messageNodes)
{
NodeRef messageNode = messageChildRef.getChildRef();
nodeService.deleteNode(messageNode);
}
}
/**
* Clear Repo Bundle
*/
private void assertMessageValue(String errorMessage, String expectedValue, String key, Locale locale)
{
transactionService.getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
assertEquals(errorMessage, expectedValue, messageService.getMessage(key, locale));
return null;
}
});
}
}

View File

@@ -25,9 +25,14 @@
*/
package org.alfresco.repo.dictionary;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
@@ -53,8 +58,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import javax.transaction.UserTransaction;
import org.springframework.transaction.annotation.Transactional;
@Category(BaseSpringTestsCategory.class)
@@ -94,6 +97,14 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
"</model>";
public static final String MESSAGES_KEY = "my_bootstrap_test";
public static final String MESSAGES_VALUE = "My Message";
public static final String MESSAGES_VALUE_FR = "Mon message";
public static final String FOLDERNAME_MODELS = "models";
public static final String FOLDERNAME_MESSAGES = "messages";
public static final String BUNDLENAME_MESSAGES = "testBootstap";
public static final String FILENAME_MESSAGES_EXT = ".properties";
/** Behaviour filter */
private BehaviourFilter behaviourFilter;
@@ -123,7 +134,8 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
private UserTransaction txn;
private StoreRef storeRef;
private NodeRef rootNodeRef;
private NodeRef rootModelsNodeRef;
private NodeRef rootMessagesNodeRef;
@Before
public void before() throws Exception
@@ -151,7 +163,17 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
// Create the store and get the root node
this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
this.rootNodeRef = this.nodeService.getRootNode(this.storeRef);
NodeRef rootNodeRef = this.nodeService.getRootNode(this.storeRef);
this.rootModelsNodeRef = this.nodeService
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MODELS), ContentModel.TYPE_FOLDER)
.getChildRef();
this.rootMessagesNodeRef = this.nodeService
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MESSAGES), ContentModel.TYPE_FOLDER)
.getChildRef();
txn.commit();
@@ -167,18 +189,20 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
this.bootstrap.setNamespaceService(this.namespaceService);
this.bootstrap.setMessageService(this.messageService);
this.bootstrap.setPolicyComponent(this.policyComponent);
RepositoryLocation location = new RepositoryLocation();
location.setStoreProtocol(this.storeRef.getProtocol());
location.setStoreId(this.storeRef.getIdentifier());
location.setQueryLanguage(RepositoryLocation.LANGUAGE_PATH);
// NOTE: we are not setting the path for now .. in doing so we are searching the root node only
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
locations.add(location);
this.bootstrap.setRepositoryModelsLocations(locations);
RepositoryLocation modelsLocation = new RepositoryLocation(this.storeRef,
this.nodeService.getPath(rootModelsNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
RepositoryLocation messagesLocation = new RepositoryLocation(this.storeRef,
this.nodeService.getPath(rootMessagesNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
List<RepositoryLocation> modelsLocations = new ArrayList<RepositoryLocation>();
modelsLocations.add(modelsLocation);
List<RepositoryLocation> messagesLocations = new ArrayList<RepositoryLocation>();
messagesLocations.add(messagesLocation);
this.bootstrap.setRepositoryModelsLocations(modelsLocations);
this.bootstrap.setRepositoryMessagesLocations(messagesLocations);
// register with dictionary service
this.bootstrap.register();
txn.commit();
@@ -224,7 +248,15 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
"Test model one",
"base1",
"prop1");
// Create a message file for the default locale
NodeRef messageNodeDefaultLoc = createMessagesNode(null, null);
// Create a message file for the french locale
createMessagesNode(Locale.FRANCE.toString(), MESSAGES_VALUE_FR);
// Construct baseBundleName for validation
String baseBundleName = storeRef.toString()
+ messageService.getBaseBundleName(nodeService.getPath(messageNodeDefaultLoc).toPrefixString(namespaceService));
// Check that the model is not in the dictionary yet
try
{
@@ -251,6 +283,12 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
QName.createQName("http://www.alfresco.org/model/test3DictionaryBootstrapFromRepo/1.0", "testModel3"));
assertNotNull(modelDefinition3);
// Check if the messages were registered correctly
assertTrue("The message bundle should be registered", messageService.getRegisteredBundles().contains(baseBundleName));
assertEquals("The default message value is not as expected", MESSAGES_VALUE, messageService.getMessage(MESSAGES_KEY));
assertEquals("The message value in french is not as expected", MESSAGES_VALUE_FR,
messageService.getMessage(MESSAGES_KEY, Locale.FRANCE));
txn.commit();
}
@@ -277,7 +315,7 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
{
// Create a model node
NodeRef model = this.nodeService.createNode(
this.rootNodeRef,
this.rootModelsNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}models"),
ContentModel.TYPE_DICTIONARY_MODEL).getChildRef();
@@ -300,6 +338,39 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
return model;
}
/**
* Create messages node
*
* @return NodeRef
*/
private NodeRef createMessagesNode(String locale, String localeValue)
{
String filename = BUNDLENAME_MESSAGES + FILENAME_MESSAGES_EXT;
String messageValue = MESSAGES_VALUE;
if (locale != null)
{
filename = BUNDLENAME_MESSAGES + "_" + locale + FILENAME_MESSAGES_EXT;
messageValue = localeValue;
}
// Create a model node
NodeRef messageNode = this.nodeService.createNode(
this.rootMessagesNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
ContentModel.TYPE_CONTENT,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
).getChildRef();
ContentWriter contentWriter = this.contentService.getWriter(messageNode, ContentModel.PROP_CONTENT, true);
contentWriter.setEncoding("UTF-8");
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
String messagesString = MESSAGES_KEY + "=" + messageValue;
contentWriter.putContent(messagesString);
return messageNode;
}
/**
*
* Gets the model string

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -96,6 +96,8 @@ public abstract class AbstractPermissionTest extends TestCase
protected NodeRef systemNodeRef;
protected NodeRef abstainedNode;
protected AuthenticationComponent authenticationComponent;
protected ModelDAO permissionModelDAO;
@@ -186,6 +188,8 @@ public abstract class AbstractPermissionTest extends TestCase
props = createPersonProperties(USER2_LEMUR);
nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef();
abstainedNode= nodeService.createNode(rootNodeRef, ContentModel.ASSOC_FAILED_THUMBNAIL, system, ContentModel.TYPE_FAILED_THUMBNAIL).getChildRef();
// create an authentication object e.g. the user
if(authenticationDAO.userExists(USER1_ANDY))
{

View File

@@ -0,0 +1,181 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Set;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ACLEntryVoterUtilsTest
{
private final NodeRef testNodeRef = new NodeRef("workspace://testNodeRef/testNodeRef");
private final NodeRef rootNodeRef = new NodeRef("workspace://rootNodeRef/rootNodeRef");
private final NodeRef refNodeForTestObject = new NodeRef("workspace://refNodeForTestObject/refNodeForTestObject");
private final NodeRef childRefNode = new NodeRef("workspace://childRefNode/childRefNode");
private final StoreRef testStoreNodeRef = new StoreRef("system://testStoreRefMock/testStoreRefMock");
private final SimplePermissionReference simplePermissionReference = SimplePermissionReference.getPermissionReference(QName.createQName("uri", "local"), "Write");
private final QName qNameToAbstain1 = QName.createQName("{test}testnode1");
private final QName qNameToAbstain2 = QName.createQName("{test}testnode2");
private final QName qNameToAbstain3 = QName.createQName("{test}testnode3");
private final QName qNameNotFromTheAbstainSet = QName.createQName("{test}testnodeAbstain");
private final Set<QName> qNamesToAbstain = Set.of(qNameToAbstain1, qNameToAbstain2, qNameToAbstain3);
@Mock
private PermissionService permissionServiceMock;
@Mock
private NodeService nodeServiceMock;
@Mock
private ChildAssociationRef childAssocRefMock;
@Before
public void setUp()
{
when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.TRUE);
when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.TRUE);
when(nodeServiceMock.getRootNode(testStoreNodeRef)).thenReturn(rootNodeRef);
when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameNotFromTheAbstainSet);
when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet));
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.DENIED);
}
@Test
public void returnsAccessDeniedFromPermissionService()
{
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_DENIED));
}
@Test
public void returnsNullOnNullTestObject()
{
assertThat(getNodeRef(null, nodeServiceMock), is(nullValue()));
}
@Test(expected = ACLEntryVoterException.class)
public void throwsExceptionWhenParameterIsNotNodeRefOrChildAssociationRef()
{
getNodeRef("TEST", nodeServiceMock);
}
@Test
public void returnsGivenTestNodeRefWhenStoreRefDoesNotExist()
{
when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.FALSE);
assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(nullValue()));
}
@Test
public void returnsRootNode()
{
assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(rootNodeRef));
}
@Test
public void returnsNodeRefFromTestObject()
{
assertThat(getNodeRef(refNodeForTestObject, nodeServiceMock), is(refNodeForTestObject));
}
@Test
public void returnsChildRefFromChildAssocRef()
{
when(childAssocRefMock.getChildRef()).thenReturn(childRefNode);
assertThat(getNodeRef(childAssocRefMock, nodeServiceMock), is(childRefNode));
}
@Test
public void returnsNullOnNullTestNodeRef()
{
assertThat(shouldAbstainOrDeny(simplePermissionReference, null, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnAbstainClassQnamesIsEmptyAndThereAreNoDeniedPermissions()
{
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, Collections.emptySet(), nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnTestNodeRefDoesNotExistAndThereAreNoDeniedPermissions()
{
when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.FALSE);
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnNodeTypeAndNodeAspectsAreNotInSetToAbstainAndThereAreNoDeniedPermissions()
{
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsAbstainWhenNodeRefTypeIsInSetToAbstain()
{
when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameToAbstain2);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_ABSTAIN));
}
@Test
public void returnsAbstainWhenAtLeastOneAspectIsInSetToAbstain()
{
when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet, qNameToAbstain3));
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_ABSTAIN));
}
}

View File

@@ -0,0 +1 @@
mycustommessages.key1=This is a custom message

View File

@@ -0,0 +1 @@
mycustommessages.key1=Dies ist eine benutzerdefinierte Nachricht

View File

@@ -0,0 +1 @@
mycustommessages.key1=Ceci est un message personnalis\u00e9