/
LightAdminRolesTest.java
2666 lines (2554 loc) · 146 KB
/
LightAdminRolesTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 2017 University of Dundee & Open Microscopy Environment.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package integration;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import ome.model.enums.DetectorType;
import ome.model.enums.EventType;
import omero.RLong;
import omero.RString;
import omero.SecurityViolation;
import omero.ServerError;
import omero.api.IRenderingSettingsPrx;
import omero.api.IScriptPrx;
import omero.api.ITypesPrx;
import omero.api.IUpdatePrx;
import omero.api.RawFileStorePrx;
import omero.api.SearchPrx;
import omero.api.ServiceFactoryPrx;
import omero.cmd.Chgrp2;
import omero.cmd.Chown2;
import omero.gateway.util.Requests;
import omero.gateway.util.Requests.Delete2Builder;
import omero.gateway.util.Utils;
import omero.model.AdminPrivilege;
import omero.model.AdminPrivilegeI;
import omero.model.ContrastMethod;
import omero.model.ContrastMethodI;
import omero.model.Dataset;
import omero.model.DatasetImageLink;
import omero.model.DatasetImageLinkI;
import omero.model.Experimenter;
import omero.model.ExperimenterGroup;
import omero.model.ExperimenterGroupI;
import omero.model.ExperimenterI;
import omero.model.FileAnnotation;
import omero.model.IObject;
import omero.model.Image;
import omero.model.ImageAnnotationLink;
import omero.model.ImageI;
import omero.model.NamedValue;
import omero.model.OriginalFile;
import omero.model.OriginalFileI;
import omero.model.PermissionsI;
import omero.model.Pixels;
import omero.model.Project;
import omero.model.ProjectDatasetLink;
import omero.model.ProjectDatasetLinkI;
import omero.model.RectangleI;
import omero.model.RenderingDef;
import omero.model.Roi;
import omero.model.RoiI;
import omero.model.TagAnnotation;
import omero.model.TagAnnotationI;
import omero.model.enums.AdminPrivilegeChgrp;
import omero.model.enums.AdminPrivilegeChown;
import omero.model.enums.AdminPrivilegeDeleteFile;
import omero.model.enums.AdminPrivilegeDeleteManagedRepo;
import omero.model.enums.AdminPrivilegeDeleteOwned;
import omero.model.enums.AdminPrivilegeDeleteScriptRepo;
import omero.model.enums.AdminPrivilegeModifyGroup;
import omero.model.enums.AdminPrivilegeModifyGroupMembership;
import omero.model.enums.AdminPrivilegeModifyUser;
import omero.model.enums.AdminPrivilegeSudo;
import omero.model.enums.AdminPrivilegeWriteFile;
import omero.model.enums.AdminPrivilegeWriteManagedRepo;
import omero.model.enums.AdminPrivilegeWriteOwned;
import omero.model.enums.AdminPrivilegeWriteScriptRepo;
import omero.sys.EventContext;
import omero.sys.ParametersI;
import org.apache.commons.io.FileUtils;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests the concrete workflows of the light admins
* @author p.walczysko@dundee.ac.uk
* @since 5.4.0
*/
public class LightAdminRolesTest extends RolesTests {
@Override
@AfterClass
public void tearDown() throws Exception {
final ITypesPrx svc = root.getSession().getTypesService();
svc.resetEnumerations(ContrastMethod.class.getName());
svc.resetEnumerations(DetectorType.class.getName());
super.tearDown();
}
/**
* Creates a new administrator without any privileges
* and create a new {@link omero.client}.
*/
protected EventContext logNewAdminWithoutPrivileges() throws Exception {
return loginNewAdmin(true, Collections.<String>emptyList());
}
/**
* Create a light administrator, with a specific privilege, and log in as them.
* All the other privileges will be set to false.
* @param isAdmin if the user should be a member of the <tt>system</tt> group
* @param permission the privilege that the user should have, or {@code null} if they should have no privileges
* @return the new user's context
* @throws Exception if the light administrator could not be created
*/
private EventContext loginNewAdmin(boolean isAdmin, String permission) throws Exception {
final EventContext ctx = loginNewAdmin(isAdmin, Arrays.asList(permission));
return ctx;
}
/**
* Create a light administrator, with a specific list of privileges, and log in as them.
* All the other privileges will be set to False.
* @param isAdmin if the user should be a member of the <tt>system</tt> group
* @param permissions the privileges that the user should have, or {@code null} if they should have no privileges
* @return the new user's context
* @throws Exception if the light administrator could not be created
*/
private EventContext loginNewAdmin(boolean isAdmin, List <String> permissions) throws Exception {
final ServiceFactoryPrx rootSession = root.getSession();
final EventContext ctx = isAdmin ? newUserInGroup(rootSession.getAdminService().lookupGroup(roles.systemGroupName), false)
: newUserAndGroup("rwr-r-");
Experimenter user = new ExperimenterI(ctx.userId, false);
user = (Experimenter) rootSession.getQueryService().get("Experimenter", ctx.userId);
final List<AdminPrivilege> privileges = Utils.toEnum(AdminPrivilege.class, AdminPrivilegeI.class, permissions);
rootSession.getAdminService().setAdminPrivileges(user, Collections.<AdminPrivilege>emptyList());
rootSession.getAdminService().setAdminPrivileges(user, privileges);
/* avoid old session as privileges are briefly cached */
loginUser(ctx);
return ctx;
}
/**
* Sudo to the given user.
* @param target a user
* @throws Exception if the sudo could not be performed
*/
private void sudo(Experimenter target) throws Exception {
if (!target.isLoaded()) {
target = iAdmin.getExperimenter(target.getId().getValue());
}
sudo(target.getOmeName().getValue());
}
/**
* Annotate image with tag and file annotation and return the annotation objects
* including the original file of the file annotation and the links
* @param image the image to be annotated
* @return the list of the tag, original file of the file annotation, file annotation
* and the links between the tag and image and the file annotation and image
* @throws Exception
*/
private List<IObject> annotateImageWithTagAndFile(Image image) throws Exception {
TagAnnotation tagAnnotation = new TagAnnotationI();
tagAnnotation = (TagAnnotation) iUpdate.saveAndReturnObject(tagAnnotation);
final ImageAnnotationLink tagAnnotationLink = linkParentToChild(image, tagAnnotation);
/* add a file attachment with original file to the imported image.*/
final ImageAnnotationLink fileAnnotationLink = linkParentToChild(image, mmFactory.createFileAnnotation());
/* link was saved in previous step with the whole graph, including fileAnnotation and original file */
final FileAnnotation fileAnnotation = (FileAnnotation) fileAnnotationLink.getChild();
final OriginalFile annotOriginalFile = fileAnnotation.getFile();
/* make a list of annotation objects in order to simplify checking of owner and group */
List<IObject> annotOriginalFileAnnotationTagAndLinks = new ArrayList<IObject>();
annotOriginalFileAnnotationTagAndLinks.addAll(Arrays.asList(annotOriginalFile, fileAnnotation, tagAnnotation,
tagAnnotationLink, fileAnnotationLink));
return annotOriginalFileAnnotationTagAndLinks;
}
/**
* Light administrator (lightAdmin) tries to create new Project and Dataset and set normalUser as
* the owner of the Project and Dataset in a group where lightAdmin is not member (normalUser's group).
* lightAdmin tries the creation above both sudoing and not sudoing as normalUser
* and both having and not having <tt>WriteOwned</tt> privilege.
* The test finishes for test cases in which lightAdmin does not sudo after the creation attempt above.
* For cases in which lightAdmin does Sudo as normalUser:
* lightAdmin tries to import data on behalf of normalUser into the just created Dataset.
* lightAdmin, still sudoed as normalUser, tries then to link the Dataset to the Project.
* Non-sudoing workflows for import and linking are too complicated to be included in this test.
* Those two actions are covered by separate tests ({@link #testImporterAsNoSudoChownOnlyWorkflow testImporterAsNoSudoChownOnly},
* {@link #testImporterAsNoSudoChgrpChownWorkflow testImporterAsNoSudoChgrpChown} and {@link #testLinkNoSudo testLinkNoSudo}).
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permWriteOwned if to test a user who has the <tt>WriteOwned</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testImporterAsSudoCreateImport.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and WriteOwned privileges cases")
public void testImporterAsSudoCreateImport(boolean isSudoing, boolean permWriteOwned,
String groupPermissions) throws Exception {
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* Only WriteOwned permission is needed for creation of objects when not sudoing.
* When sudoing, no other permission is needed.*/
final boolean isExpectSuccessCreate = permWriteOwned || isSudoing;
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permWriteOwned) permissions.add(AdminPrivilegeWriteOwned.value);
loginNewAdmin(true, permissions);
/* lightAdmin possibly sudoes on behalf of normalUser, depending on test case.*/
if (isSudoing) sudo(new ExperimenterI(normalUser.userId, false));
/* lightAdmin tries to create Project and Dataset on behalf of the normalUser
* in normalUser's group.*/
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
Project proj = mmFactory.simpleProject();
Dataset dat = mmFactory.simpleDataset();
Project sentProj = null;
Dataset sentDat = null;
/* lightAdmin sets the normalUser as the owner of the newly created Project/Dataset but only
* in cases in which lightAdmin is not sudoing (if sudoing, the created Project/Dataset
* already belong to normalUser).*/
if (!isSudoing) {
proj.getDetails().setOwner(new ExperimenterI(normalUser.userId, false));
dat.getDetails().setOwner(new ExperimenterI(normalUser.userId, false));
}
/* Check lightAdmin can or cannot save the created Project and Dataset as appropriate
* (see definition of isExpectSuccessCreate above).*/
try {
sentProj = (Project) iUpdate.saveAndReturnObject(proj);
sentDat = (Dataset) iUpdate.saveAndReturnObject(dat);
Assert.assertTrue(isExpectSuccessCreate);
} catch (ServerError se) {
Assert.assertFalse(isExpectSuccessCreate);
}
/* Check the owner of the Project and Dataset (P/D) is the normalUser in all cases
* the P/D were created, in all other cases P/D should be null.*/
if (isExpectSuccessCreate) {
assertOwnedBy(sentProj, normalUser);
assertOwnedBy(sentDat, normalUser);
} else {
Assert.assertNull(sentProj);
Assert.assertNull(sentDat);
}
/* Finish the test if lightAdmin is not sudoing.
* Further tests of this test method deal with import and linking
* for normalUser by lightAdmin who sudoes on behalf of normalUser.
* Imports and linking for others while NOT using Sudo
* are covered in other test methods in this class.*/
if (!isSudoing) return;
/* Check that after sudo, lightAdmin can import and write the originalFile
* of the imported image on behalf of the normalUser into the created Dataset.*/
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
OriginalFile originalFile = (OriginalFile) originalFileAndImage.get(0);
Image image = (Image) originalFileAndImage.get(1);
/* Check the canLink() boolean for both Dataset and Project.
* lightAdmin is always sudoing in this part of the test.
* Thus canLink() is always true, because lightAdmin is sudoed
* on behalf of the owner of the objects (normalUser).*/
Assert.assertTrue(getCurrentPermissions(sentProj).canLink());
Assert.assertTrue(getCurrentPermissions(sentDat).canLink());
/* Check that being sudoed, lightAdmin can link the Project and Dataset of normalUser.*/
ProjectDatasetLink projectDatasetLink = linkParentToChild(sentProj, sentDat);
/* Check the owner of the image, its originalFile, imageDatasetLink and projectDatasetLink
* is normalUser and the image and its originalFile are in normalUser's group.*/
final IObject imageDatasetLink = iQuery.findByQuery(
"FROM DatasetImageLink WHERE child.id = :id",
new ParametersI().addId(image.getId().getValue()));
assertInGroup(originalFile, normalUser.groupId);
assertOwnedBy(originalFile, normalUser);
assertInGroup(image, normalUser.groupId);
assertOwnedBy(image, normalUser);
assertOwnedBy(imageDatasetLink, normalUser);
assertOwnedBy(projectDatasetLink, normalUser);
}
}
/**
* Test whether a light admin can delete image, Project and Dataset
* and their respective links belonging to another
* user. Behaviors of the system are explored when lightAdmin
* is and is not using <tt>Sudo</tt> privilege
* for this action.
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permDeleteOwned if to test a user who has the <tt>DeleteOwned</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testDelete.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and Delete privileges cases")
public void testDelete(boolean isSudoing, boolean permDeleteOwned,
String groupPermissions) throws Exception {
/* Only DeleteOwned permission is needed for deletion of links, Dataset
* and image (with original file) when not sudoing. When sudoing, no other
* permission is needed.*/
boolean deletePassing = permDeleteOwned || isSudoing;
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* Set up the light admin's permissions for this test */
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permDeleteOwned) permissions.add(AdminPrivilegeDeleteOwned.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
sudo(new ExperimenterI(normalUser.userId, false));
/* Create a Dataset and Project being sudoed as normalUser.*/
final Project sentProj;
final Dataset sentDat;
final OriginalFile originalFile;
final Image image;
final ProjectDatasetLink projectDatasetLink;
final DatasetImageLink datasetImageLink;
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
sentProj = (Project) iUpdate.saveAndReturnObject(mmFactory.simpleProject());
sentDat = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset());
/* Import an image for the normalUser into the normalUser's default group
* and target it into the created Dataset.*/
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
originalFile = (OriginalFile) originalFileAndImage.get(0);
image = (Image) originalFileAndImage.get(1);
assertOwnedBy(image, normalUser);
/* Link the Project and the Dataset.*/
projectDatasetLink = linkParentToChild(sentProj, sentDat);
datasetImageLink = (DatasetImageLink) iQuery.findByQuery(
"FROM DatasetImageLink WHERE child.id = :id",
new ParametersI().addId(image.getId()));
}
/* Take care of post-import workflows which do not use sudo.*/
if (!isSudoing) {
loginUser(lightAdmin);
}
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
/* Check that lightAdmin can delete the objects
* created on behalf of normalUser only if lightAdmin has sufficient permissions.
* Note that deletion of the Project
* would delete the whole hierarchy, which was successfully tested
* during writing of this test. The order of the below delete() commands
* is intentional, as the ability to delete the links and Project/Dataset/Image separately is
* tested in this way.
* Also check that the canDelete boolean on the object retrieved
* by the lightAdmin matches the deletePassing boolean.*/
Assert.assertEquals(getCurrentPermissions(datasetImageLink).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(datasetImageLink).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(projectDatasetLink).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(projectDatasetLink).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(image).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(image).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(sentDat).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(sentDat).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(sentProj).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(sentProj).build(), deletePassing);
/* Check the existence/non-existence of the objects as appropriate.*/
if (deletePassing) {
assertDoesNotExist(originalFile);
assertDoesNotExist(image);
assertDoesNotExist(sentDat);
assertDoesNotExist(sentProj);
assertDoesNotExist(datasetImageLink);
assertDoesNotExist(projectDatasetLink);
} else {
assertExists(originalFile);
assertExists(image);
assertExists(sentDat);
assertExists(sentProj);
assertExists(datasetImageLink);
assertExists(projectDatasetLink);
}
}
}
/**
* Test whether a light admin (lightAdmin) can delete image, Project and Dataset
* and their respective links belonging to another
* user (normalUser).
* Note that for this test, lightAdmin is member of normalUser's group.
* lightAdmin's privileges regarding deletion of others' data are not elevated by
* membership in the group over the privileges of normal member of group (otherUser).
* @param isAdmin if to test a success of workflows when light admin
* @param permDeleteOwned if to test a user who has the <tt>DeleteOwned</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
*/
@Test(dataProvider = "isAdmin and Delete cases")
public void testDeleteGroupMemberNoSudo(boolean isAdmin, boolean permDeleteOwned,
String groupPermissions) throws Exception {
/* Only DeleteOwned permission is needed for deletion of links, Dataset
* and image (with original file) when isAdmin. When not isAdmin, only in
* read-write group deletion of others data is possible.*/
boolean deletePassing = (permDeleteOwned && isAdmin) || groupPermissions.equals("rwrw--");
final EventContext normalUser = newUserAndGroup(groupPermissions);
final EventContext otherUser = newUserAndGroup(groupPermissions);
ExperimenterGroup normalUsergroup = new ExperimenterGroupI(normalUser.groupId, false);
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
if (permDeleteOwned) permissions.add(AdminPrivilegeDeleteOwned.value);
final EventContext lightAdmin = loginNewAdmin(true, permissions);
/* root adds lightAdmin to normalUser's group.*/
logRootIntoGroup(normalUser);
normalUsergroup = addUsers(normalUsergroup, ImmutableList.of(lightAdmin.userId, otherUser.userId), false);
/* normalUser creates a Dataset and Project.*/
loginUser(normalUser);
Project sentProj = (Project) iUpdate.saveAndReturnObject(mmFactory.simpleProject());
Dataset sentDat = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset());
/* normalUser imports an image
* and targets it into the created Dataset.*/
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
OriginalFile originalFile = (OriginalFile) originalFileAndImage.get(0);
Image image = (Image) originalFileAndImage.get(1);
assertOwnedBy(image, normalUser);
/* normalUser links the Project and the Dataset.*/
ProjectDatasetLink projectDatasetLink = linkParentToChild(sentProj, sentDat);
IObject datasetImageLink = iQuery.findByQuery(
"FROM DatasetImageLink WHERE child.id = :id",
new ParametersI().addId(image.getId()));
/* Post-import workflows are done either by lightAdmin or by otherUser.*/
if (isAdmin) {
loginUser(lightAdmin);
} else {
loginUser(otherUser);
}
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
/* Check that lightAdmin or otherUser can delete the objects
* of normalUser only if lightAdmin has sufficient permissions or it is read-write group.
* Note that deletion of the Project
* would delete the whole hierarchy, which was successfully tested
* during writing of this test. The order of the below delete() commands
* is intentional, as the ability to delete the links and Project/Dataset/Image separately is
* tested in this way.
* Also check that the canDelete boolean on the object retrieved by the lightAdmin
* or otherUser matches the deletePassing boolean.*/
Assert.assertEquals(getCurrentPermissions(datasetImageLink).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(datasetImageLink).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(projectDatasetLink).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(projectDatasetLink).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(image).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(image).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(sentDat).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(sentDat).build(), deletePassing);
Assert.assertEquals(getCurrentPermissions(sentProj).canDelete(), deletePassing);
doChange(client, factory, Requests.delete().target(sentProj).build(), deletePassing);
}
/* Check the existence/non-existence of the objects as appropriate.*/
logRootIntoGroup(normalUser);
if (deletePassing) {
assertDoesNotExist(originalFile);
assertDoesNotExist(image);
assertDoesNotExist(sentDat);
assertDoesNotExist(sentProj);
assertDoesNotExist(datasetImageLink);
assertDoesNotExist(projectDatasetLink);
} else {
assertExists(originalFile);
assertExists(image);
assertExists(sentDat);
assertExists(sentProj);
assertExists(datasetImageLink);
assertExists(projectDatasetLink);
}
}
/**
* light admin (lightAdmin) being also a group owner of one group
* (ownedGroup) tries to delete Dataset of other user (normalUser).
* lightAdmin also tries to delete data of yet one other user (otherUser)
* in a group which they do not own (notOwnedGroup).
* lightAdmin succeeds only in the ownGroup, in the notOwnedGroup they
* succeed only with DeleteOwned privilege.
* @param isPrivileged if to test a user who has the <tt>DeleteOwned</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
*/
@Test(dataProvider = "isPrivileged cases")
public void testDeleteGroupOwner(boolean isPrivileged,
String groupPermissions) throws Exception {
/* DeleteOwned privilege is necessary for deletion in group which is
* not owned. For deletion in group which is owned, no privilege is necessary.*/
boolean deletePassingNotOwnedGroup = isPrivileged;
boolean deletePassingOwnedGroup = true;
final EventContext normalUser = newUserAndGroup(groupPermissions);
final EventContext otherUser = newUserAndGroup(groupPermissions);
/* Set up the light admin's permissions for this test */
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (isPrivileged) permissions.add(AdminPrivilegeDeleteOwned.value);
final EventContext lightAdmin = loginNewAdmin(true, permissions);
ExperimenterGroup ownedGroup = new ExperimenterGroupI(normalUser.groupId, false);
ExperimenterGroup notOwnedGroup = new ExperimenterGroupI(otherUser.groupId, false);
/* root adds lightAdmin to normalUser's group as owner.*/
logRootIntoGroup(normalUser);
ownedGroup = addUsers(ownedGroup, Collections.singletonList(lightAdmin.userId), true);
/* normalUser creates a Dataset in ownGroup.*/
loginUser(normalUser);
final Dataset sentDataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset());
/* otherUser creates a Dataset in notOwnGroup.*/
loginUser(otherUser);
final Dataset sentOtherDataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset());
/* Check that the Datasets are in their groups as expected.*/
assertInGroup(sentDataset, ownedGroup);
assertInGroup(sentOtherDataset, notOwnedGroup);
/* Check that lightAdmin can delete the Datasets only when permissions allow that.
* Also check that the canDelete boolean
* on the object retrieved by the lightAdmin matches the deletePassing
* boolean.*/
loginUser(lightAdmin);
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
Assert.assertEquals(getCurrentPermissions(sentDataset).canDelete(), deletePassingOwnedGroup);
doChange(client, factory, Requests.delete().target(sentDataset).build(), deletePassingOwnedGroup);
}
try (final AutoCloseable igc = new ImplicitGroupContext(otherUser.groupId)) {
Assert.assertEquals(getCurrentPermissions(sentOtherDataset).canDelete(), deletePassingNotOwnedGroup);
doChange(client, factory, Requests.delete().target(sentOtherDataset).build(), deletePassingNotOwnedGroup);
/* Check the existence/non-existence of the objects as appropriate.*/
assertDoesNotExist(sentDataset);
if (deletePassingNotOwnedGroup) {
assertDoesNotExist(sentOtherDataset);
} else {
assertExists(sentOtherDataset);
}
}
}
/**
* Test that a light admin can edit the name of a project
* on behalf of another user either using <tt>Sudo</tt> privilege
* or not using it, but having <tt>WriteOwned</tt> privilege instead.
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permWriteOwned if to test a user who has the <tt>WriteOwned</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testEdit.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and WriteOwned privileges cases")
public void testEdit(boolean isSudoing, boolean permWriteOwned,
String groupPermissions) throws Exception {
final boolean isExpectSuccess = isSudoing || permWriteOwned;
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permWriteOwned) permissions.add(AdminPrivilegeWriteOwned.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
/* Create Project as normalUser.*/
loginUser(normalUser);
Project proj = mmFactory.simpleProject();
final String originalName = "OriginalNameOfNormalUser";
proj.setName(omero.rtypes.rstring(originalName));
Project sentProj = (Project) iUpdate.saveAndReturnObject(proj);
String savedOriginalName = sentProj.getName().getValue().toString();
loginUser(lightAdmin);
/* As lightAdmin, sudo as the normalUser if this should be the case.*/
if (isSudoing) sudo(new ExperimenterI(normalUser.userId, false));
/* Check that the canEdit flag on the created project is as expected.*/
Assert.assertEquals(getCurrentPermissions(sentProj).canEdit(), isExpectSuccess);
/* Try to rename the Project.*/
final String changedName = "ChangedNameOfLightAdmin";
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
long id = sentProj.getId().getValue();
final Project retrievedUnrenamedProject = (Project) iQuery.get("Project", id);
retrievedUnrenamedProject.setName(omero.rtypes.rstring(changedName));
/* Check that lightAdmin can edit the Project of normalUser only when
* lightAdmin is equipped with sufficient permissions, captured in boolean isExpectSuccess.*/
try {
sentProj = (Project) iUpdate.saveAndReturnObject(retrievedUnrenamedProject);
Assert.assertTrue(isExpectSuccess);
} catch (ServerError se) {
Assert.assertFalse(isExpectSuccess, se.toString());
}
}
String savedChangedName = sentProj.getName().getValue().toString();
logRootIntoGroup(normalUser.groupId);
final String retrievedName = ((RString) iQuery.projection(
"SELECT name FROM Project p WHERE p.id = :id",
new ParametersI().addId(sentProj.getId())).get(0).get(0)).getValue();
/* Check that the Project still belongs to normalUser and the name of the Project
* was changed and saved or original name is retained as appropriate.*/
assertOwnedBy(sentProj, normalUser);
if (isExpectSuccess) {
Assert.assertEquals(savedChangedName, retrievedName);
Assert.assertEquals(savedChangedName, changedName);
} else {
Assert.assertEquals(savedOriginalName, retrievedName);
Assert.assertEquals(savedOriginalName, originalName);
}
}
/**
* Test that light admin can
* chgrp on behalf of another user in cases where the user (owner of the data)
* is a member of both groups. The chgrp action succeeds if <tt>Sudo</tt> privilege
* is used. If lightAdmin does not sudo, then the <tt>Chgrp</tt> privilege is necessary.
* Also tests the ability of the <tt>Chgrp</tt> privilege and chgrp command
* to sever necessary links for performing the chgrp. This is achieved by
* having the image which is getting moved into a different group in a dataset
* in the original group (the chgrp has to sever the DatasetImageLink to perform
* the move (chgrp)). <tt>Chgrp</tt> privilege is sufficient also
* to move annotations on the moved objects (tag and file attachment are tested here).
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permChgrp if to test a user who has the <tt>Chgrp</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testChgrp.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and Chgrp privileges cases")
public void testChgrp(boolean isSudoing, boolean permChgrp, String groupPermissions)
throws Exception {
/* Set up a user and three groups, the user being a member of
* two of the groups.*/
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* Group where the user is a member.*/
final long normalUsersOtherGroupId = newGroupAddUser(groupPermissions, normalUser.userId, false).getId().getValue();
/* If normalUser (data owner) is member of target group,
* Chgrp action passes when lightAdmin is
* Sudoed as the normalUser (data owner) or when Chgrp permission is given to lightAdmin.
* A successful chgrp action will also move all annotations on the moved image,
* which are unique on the image.*/
boolean isExpectSuccessInMemberGroup = permChgrp || isSudoing;
/* Create a Dataset as normalUser and import into it.*/
loginUser(normalUser);
Dataset dat = mmFactory.simpleDataset();
Dataset sentDat = (Dataset) iUpdate.saveAndReturnObject(dat);
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
OriginalFile originalFile = (OriginalFile) originalFileAndImage.get(0);
Image image = (Image) originalFileAndImage.get(1);
/* Annotate the imported image with Tag and file attachment.*/
List<IObject> annotOriginalFileAnnotationTagAndLinks = annotateImageWithTagAndFile(image);
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permChgrp) permissions.add(AdminPrivilegeChgrp.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
sudo(new ExperimenterI(normalUser.userId, false));
/* Take care of workflows which do not use sudo.*/
if (!isSudoing) {
loginUser(lightAdmin);
}
/* In order to find the image in whatever group, get to all groups context.*/
try (final AutoCloseable igc = new ImplicitAllGroupsContext()) {
/* lightAdmin tries to move the image into another group of the normalUser
* which should succeed if sudoing and also in case
* the light admin has Chgrp permissions
* (i.e. isExpectSuccessInMemberGroup is true). Also check that
* the canChgrp boolean matches the isExpectSuccessInMemberGroup boolean value */
Assert.assertEquals(getCurrentPermissions(image).canChgrp(), isExpectSuccessInMemberGroup);
final Chgrp2 chgrpReq = Requests.chgrp().target(image).toGroup(normalUsersOtherGroupId).build();
doChange(client, factory, chgrpReq, isExpectSuccessInMemberGroup);
if (isExpectSuccessInMemberGroup) {
assertInGroup(image, normalUsersOtherGroupId);
assertInGroup(originalFile, normalUsersOtherGroupId);
/* Annotations on the image changed the group with the image.*/
assertInGroup(annotOriginalFileAnnotationTagAndLinks, normalUsersOtherGroupId);
} else {
assertInGroup(image, normalUser.groupId);
assertInGroup(originalFile, normalUser.groupId);
/* The annotations were not moved.*/
assertInGroup(annotOriginalFileAnnotationTagAndLinks, normalUser.groupId);
}
/* In any case, the image should still belong to normalUser.*/
assertOwnedBy(image, normalUser);
}
}
/**
* Tests that light admin can, having the <tt>Chgrp</tt>
* privilege move another user's data into another group where the
* owner of the data is not member.
* <tt>Sudo</tt> privilege and being sudoed should not be sufficient,
* and also, when being sudoed, the cancellation of the <tt>Chgrp</tt> privilege
* by being sudoed as normalUser causes that the move of the image fails.
* Also tests the ability of the <tt>Chgrp</tt> privilege and chgrp command
* to sever necessary links for performing the chgrp. This is achieved by
* having the image which is getting moved into a different group in a dataset
* in the original group (the chgrp has to sever the DatasetImageLink to perform
* the move (chgrp)). <tt>Chgrp</tt> privilege is sufficient also
* to move annotations (tag and file attachment are tested here).
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permChgrp if to test a user who has the <tt>Chgrp</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testChgrpNonMember.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and Chgrp privileges cases")
public void testChgrpNonMember(boolean isSudoing, boolean permChgrp, String groupPermissions)
throws Exception {
/* Set up a user (normalUser) and two groups, the normalUser being a member of
* only one of the groups.*/
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* group where the normalUser is not member */
final long anotherGroupId = newUserAndGroup(groupPermissions).groupId;
/* When normalUser (data owner) is not member of the target group,
* Chgrp action passes only when lightAdmin has Chgrp permission
* and lightAdmin is not Sudoing. This permission situation should be also valid
* for all annotations on the image which are unique on the image (not used
* anywhere else).*/
boolean chgrpNonMemberExpectSuccess = !isSudoing && permChgrp;
/* Define cases where canChgrp on the image is expected to be true.
* As the canChgrp boolean cannot "know" in advance to which group the
* move is intended, it must show "true" in every case in which SOME
* chgrp might be successful.*/
final boolean canChgrpExpectedTrue = permChgrp || isSudoing;
/* Create a Dataset as the normalUser and import into it.*/
loginUser(normalUser);
Dataset dat = mmFactory.simpleDataset();
Dataset sentDat = (Dataset) iUpdate.saveAndReturnObject(dat);
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
OriginalFile originalFile = (OriginalFile) originalFileAndImage.get(0);
Image image = (Image) originalFileAndImage.get(1);
/* Annotate the imported image with Tag and file attachment.*/
List<IObject> annotOriginalFileAnnotationTagAndLinks = annotateImageWithTagAndFile(image);
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permChgrp) permissions.add(AdminPrivilegeChgrp.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
sudo(new ExperimenterI(normalUser.userId, false));
/* Take care of workflows which do not use sudo.*/
if (!isSudoing) {
loginUser(lightAdmin);
}
/* In order to find the image in whatever group, get all groups context.*/
try (final AutoCloseable igc = new ImplicitAllGroupsContext()) {
/* Try to move the image into anotherGroup the normalUser
* is not a member of, which should fail in all cases
* except the lightAdmin has Chgrp permission and is not sudoing
* (i.e. chgrpNoSudoExpectSuccessAnyGroup is true). Also check the
* the canChgrp boolean.*/
Assert.assertEquals(getCurrentPermissions(image).canChgrp(), canChgrpExpectedTrue);
doChange(client, factory, Requests.chgrp().target(image).toGroup(anotherGroupId).build(),
chgrpNonMemberExpectSuccess);
if (chgrpNonMemberExpectSuccess) {
/* Check that the image and its original file moved to another group.*/
assertInGroup(image, anotherGroupId);
assertInGroup(originalFile, anotherGroupId);
/* check the annotations on the image changed the group as expected */
assertInGroup(annotOriginalFileAnnotationTagAndLinks, anotherGroupId);
} else {
/* Check that the image is still in its original group (normalUser's group).*/
assertInGroup(image, normalUser.groupId);
assertInGroup(originalFile, normalUser.groupId);
/* The annotations stayed with the image in the normalUser's group.*/
assertInGroup(annotOriginalFileAnnotationTagAndLinks, normalUser.groupId);
}
/* In any case, the image should still belong to normalUser.*/
assertOwnedBy(image, normalUser);
}
}
/**
* Test that light admin can, having the <tt>Chown</tt> privilege,
* transfer the data between two users (normalUser and anotherUser).
* Test also that light admin, if sudoed, cannot transfer ownership,
* because light admin sudoes as a non-admin non-group-owner user.
* In case of private group the transfer of an Image severs the link between the Dataset and Image.
* For this unlinking, only the Chown permissions are sufficient, no other permissions are necessary.
* <tt>Chown</tt> privilege is sufficient also
* to transfer ownership of annotations (tag and file attachment are tested here),
* but just in case of private and read-only groups, which is in line with the
* general behavior of the <tt>Chown</tt> command.
* @param isSudoing if to test a success of workflows where Sudoed in
* @param permChown if to test a user who has the <tt>Chown</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testChown.pptx">graphical explanation</a>
*/
@Test(dataProvider = "isSudoing and Chown privileges cases")
public void testChown(boolean isSudoing, boolean permChown, String groupPermissions)
throws Exception {
/* Define the conditions for the chown of the image is passing.*/
final boolean chownImagePassing = permChown && !isSudoing;
/* Chown of the annotations on the image is passing when
* chownImagePassing is true in higher permissions groups (read-annotate and read-write)
* only.*/
final boolean annotationsChownExpectSuccess = chownImagePassing &&
(groupPermissions.equals("rw----") || groupPermissions.equals("rwr---"));
final EventContext normalUser = newUserAndGroup(groupPermissions);
final EventContext anotherUser = newUserAndGroup(groupPermissions);
/* Create a Dataset as the normalUser and import into it */
loginUser(normalUser);
Dataset dat = mmFactory.simpleDataset();
Dataset sentDat = (Dataset) iUpdate.saveAndReturnObject(dat);
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
OriginalFile originalFile = (OriginalFile) originalFileAndImage.get(0);
Image image = (Image) originalFileAndImage.get(1);
/* Annotate the imported image with Tag and file attachment.*/
List<IObject> annotOriginalFileAnnotationTagAndLinks = annotateImageWithTagAndFile(image);
/* Set up the basic permissions for this test.*/
List<String> permissions = new ArrayList<String>();
permissions.add(AdminPrivilegeSudo.value);
if (permChown) permissions.add(AdminPrivilegeChown.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
sudo(new ExperimenterI(normalUser.userId, false));
/* Take care of workflows which do not use sudo.*/
if (!isSudoing) {
loginUser(lightAdmin);
}
/* Check that the value of canChown boolean matches chownPassingWhenNotSudoing
* boolean in each case.*/
Assert.assertEquals(getCurrentPermissions(image).canChown(), chownImagePassing);
/* Get into correct group context and check all cases.*/
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
/* lightAdmin tries to chown the image.*/
doChange(client, factory, Requests.chown().target(image).toUser(anotherUser.userId).build(), chownImagePassing);
/* ChecK the results of the chown when lightAdmin is sudoed,
* which should fail in any case.*/
if (isSudoing) {
assertOwnedBy(image, normalUser);
assertOwnedBy(originalFile, normalUser);
assertOwnedBy(annotOriginalFileAnnotationTagAndLinks, normalUser);
/* Check the chown was successful for both the image and the annotations
* when the permissions for chowning both
* the image as well as the annotations on it are sufficient.*/
} else if (chownImagePassing && annotationsChownExpectSuccess) {
assertOwnedBy(image, anotherUser);
assertOwnedBy(originalFile, anotherUser);
/* Annotations will be chowned because
* groupPermissions are private or read-only (captured in boolean
* annotationsChownExpectSuccess).*/
assertOwnedBy(annotOriginalFileAnnotationTagAndLinks, anotherUser);
/* Check the chown was successful for the image but not the annotations
* in case the annotationsChownExpectSuccess is false, i.e. in read-only and private group.*/
} else if (chownImagePassing && !annotationsChownExpectSuccess){
assertOwnedBy(image, anotherUser);
assertOwnedBy(originalFile, anotherUser);
assertOwnedBy(annotOriginalFileAnnotationTagAndLinks, normalUser);
} else {
/* In the remaining case, the chown will fail, as the chownPassingWhenNotSudoing
* is false because permChown was not given. All objects belong to normalUser.*/
assertOwnedBy(image, normalUser);
assertOwnedBy(originalFile, normalUser);
assertOwnedBy(annotOriginalFileAnnotationTagAndLinks, normalUser);
}
/* In any case, the image must be in the right group.*/
assertInGroup(image, normalUser.groupId);
}
}
/**
* Light admin is trying to "import for others" without using Sudo in following manner.
* lightAdmin imports into group of the normalUser (future owner of the data).
* lightAdmin then transfers the ownership of the imported data to normalUser.
* For this test, combinations of <tt>WriteOwned</tt>, <tt>WriteFile</tt>,
* <tt>WriteManagedRepo</tt> and <tt>Chown</tt> privileges will be explored
* for lightAdmin. For this workflow the creation and targeting of a Dataset
* is tested too.
* @param permWriteOwned if to test a user who has the <tt>WriteOwned</tt> privilege
* @param permWriteFile if to test a user who has the <tt>WriteFile</tt> privilege
* @param permWriteManagedRepo if to test a user who has the <tt>WriteManagedRepo</tt> privilege
* @param permChown if to test a user who has the <tt>Chown</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testImporterAsNoSudoChownOnlyWorkflow.pptx">graphical explanation</a>
*/
@Test(dataProvider = "WriteOwned, WriteFile, WriteManagedRepo and Chown privileges cases")
public void testImporterAsNoSudoChownOnlyWorkflow(boolean permWriteOwned, boolean permWriteFile,
boolean permWriteManagedRepo, boolean permChown, String groupPermissions) throws Exception {
/* Define case in which the import not using sudo and importing into a group
* the light admin is not a member of is expected to succeed.*/
boolean importNotYourGroupExpectSuccess = permWriteOwned && permWriteFile && permWriteManagedRepo;
/* Define case in which the creation of Dataset belonging to lightAdmin
* in a group where lightAdmin is not member is expected to succeed.*/
boolean createDatasetExpectSuccess = permWriteOwned;
/* Define case in which the whole workflow is possible (as lightAdmin create
* Dataset, import into it, then chown the Dataset with the imported
* image to normalUser).*/
boolean createDatasetImportNotYourGroupAndChownExpectSuccess =
permChown && permWriteManagedRepo && permWriteOwned && permWriteFile;
final EventContext normalUser = newUserAndGroup(groupPermissions);
/* Set up the light admin's permissions for this test.*/
List<String> permissions = new ArrayList<String>();
if (permChown) permissions.add(AdminPrivilegeChown.value);
if (permWriteOwned) permissions.add(AdminPrivilegeWriteOwned.value);
if (permWriteFile) permissions.add(AdminPrivilegeWriteFile.value);
if (permWriteManagedRepo) permissions.add(AdminPrivilegeWriteManagedRepo.value);
final EventContext lightAdmin;
lightAdmin = loginNewAdmin(true, permissions);
/* lightAdmin creates Dataset in the normalUser's group
* (lightAdmin is not member of that group).*/
try (final AutoCloseable igc = new ImplicitGroupContext(normalUser.groupId)) {
Dataset dat = mmFactory.simpleDataset();
Dataset sentDat = null;
/* Creation of Dataset success is governed by
* createDatasetExpectSuccess boolean (defined above).*/
try {
sentDat = (Dataset) iUpdate.saveAndReturnObject(dat);
Assert.assertTrue(createDatasetExpectSuccess);
} catch (ServerError se) {
Assert.assertFalse(createDatasetExpectSuccess, se.toString());
}
/* As lightAdmin, import an Image into the created Dataset.*/
OriginalFile originalFile = null;
Image image = null;
/* Import success is governed by importNotYourGroupExpectSuccess boolean (defined above).*/
try {
List<IObject> originalFileAndImage = importImageWithOriginalFile(sentDat);
originalFile = (OriginalFile) originalFileAndImage.get(0);
image = (Image) originalFileAndImage.get(1);
Assert.assertTrue(importNotYourGroupExpectSuccess);
} catch (ServerError se) {
Assert.assertFalse(importNotYourGroupExpectSuccess, se.toString());
}
/* Check the ownership and group of the original file and the image.*/
if (importNotYourGroupExpectSuccess) {
assertOwnedBy(originalFile, lightAdmin);
assertInGroup(originalFile, normalUser.groupId);
assertOwnedBy(image, lightAdmin);
assertInGroup(image, normalUser.groupId);
/* In case the import was not successful, Image does not exist.
* Further testing is not interesting in such case.*/
} else {
Assert.assertNull(originalFile, "if import failed, the originalFile should be null");
Assert.assertNull(image, "if import failed, the image should be null");
return;
}
/* Check that the canChown value on the Dataset matches the boolean
* createDatasetImportNotYourGroupAndChownExpectSuccess.*/
Assert.assertEquals(getCurrentPermissions(sentDat).canChown(),
createDatasetImportNotYourGroupAndChownExpectSuccess);
/* lightAdmin tries to change the ownership of the Dataset to normalUser.*/
doChange(client, factory, Requests.chown().target(sentDat).toUser(normalUser.userId).build(),
createDatasetImportNotYourGroupAndChownExpectSuccess);
final DatasetImageLink link = (DatasetImageLink) iQuery.findByQuery(
"FROM DatasetImageLink WHERE parent.id = :id",
new ParametersI().addId(sentDat.getId()));
/* Check that image, dataset and link are in the normalUser's group
* and belong to normalUser in case the workflow succeeded.*/
if (createDatasetImportNotYourGroupAndChownExpectSuccess) {
assertOwnedBy(image, normalUser);
assertInGroup(image, normalUser.groupId);
assertOwnedBy(sentDat, normalUser);
assertInGroup(sentDat, normalUser.groupId);
assertOwnedBy(link, normalUser);
assertInGroup(link, normalUser.groupId);
assertOwnedBy(originalFile, normalUser);
assertInGroup(originalFile, normalUser.groupId);
/* Check that the image, dataset and link still belong
* to lightAdmin as the chown failed, but are in the group of normalUser.*/
} else {
assertOwnedBy(image, lightAdmin);
assertInGroup(image, normalUser.groupId);
assertOwnedBy(sentDat, lightAdmin);
assertInGroup(sentDat, normalUser.groupId);
assertOwnedBy(link, lightAdmin);
assertInGroup(link, normalUser.groupId);
}
}
}
/**
* lightAdmin tries to link an object to a pre-existing container (Dataset or Project)
* in the target group (of normalUser where lightAdmin is not member).
* lightAdmin tries to link image or Dataset to Dataset or Project.
* The image import (by lightAdmin for others) has been tested in other tests.
* Here, normalUser creates and saves the image, Dataset and Project,
* then lightAdmin tries to link these objects.
* lightAdmin will succeed if they have WriteOwned privilege.
* @param permWriteOwned if to test a user who has the <tt>WriteOwned</tt> privilege
* @param permChown if to test a user who has the <tt>Chown</tt> privilege
* @param groupPermissions to test the effect of group permission level
* @throws Exception unexpected
* @see <a href="https://downloads.openmicroscopy.org/resources/experimental/tests/graph-permissions/0.1/testLinkNoSudo.pptx">graphical explanation</a>
*/
@Test(dataProvider = "WriteOwned and Chown privileges cases")