/* * Copyright 2006 University of Dundee. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.server.itests.sec; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.UUID; import ome.annotations.RolesAllowed; import ome.api.IQuery; import ome.model.IObject; import ome.model.annotations.Annotation; import ome.model.annotations.ExperimenterAnnotationLink; import ome.model.annotations.FileAnnotation; import ome.model.containers.Dataset; import ome.model.containers.Project; import ome.model.core.Image; import ome.model.internal.Permissions; import ome.model.internal.Permissions.Right; import ome.model.internal.Permissions.Role; import ome.model.meta.Experimenter; import ome.parameters.Filter; import ome.parameters.Parameters; import ome.security.AdminAction; import ome.server.itests.AbstractManagedContextTest; import ome.services.query.Definitions; import ome.services.query.Query; import ome.services.query.QueryParameterDef; import ome.services.util.Executor; import ome.system.Principal; import ome.system.ServiceFactory; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.criterion.Restrictions; import org.springframework.transaction.annotation.Transactional; import org.testng.annotations.Test; @Test(groups = { "ticket:117", "security", "filter" }) public class SecurityFilterTest extends AbstractManagedContextTest { static String ticket117 = "ticket:117"; Executor ex; @Test public void testFilterDisallowsRead() throws Exception { Image i; Experimenter e = loginNewUser(Permissions.PRIVATE); i = createImage(); loginNewUserInOtherUsersGroup(e); assertCannotReadImage(i); loginUserKeepGroup(e); assertCanReadImage(i); } @Test public void testRootCanReadAll() throws Exception { Image i; Experimenter e = loginNewUser(Permissions.PRIVATE); i = createImage(); assertCanReadImage(i); loginNewUserInOtherUsersGroup(e); assertCannotReadImage(i); loginRootKeepGroup(); assertCanReadImage(i); } @Test public void testRunAsAdminCanReadAll() throws Exception { final Image i; final Dataset d; Experimenter e = loginNewUser(Permissions.PRIVATE); d = createDataset(); i = createImage(); loginNewUserInOtherUsersGroup(e); assertCannotReadImage(d, i); final SecurityFilterTest test = this; String uuid = (String) applicationContext.getBean("uuid"); ex = (Executor) applicationContext.getBean("executor"); ex.execute(new Principal(uuid), new Executor.SimpleWork(this, "run as admin") { @RolesAllowed("user") @Transactional(readOnly=true) public Object doWork(org.hibernate.Session session, final ServiceFactory sf) { securitySystem.runAsAdmin(new AdminAction() { public void runAsAdmin() { assertCanReadImage(sf.getQueryService(), i); } }); return null; } }); loginUserKeepGroup(e); assertCanReadImage(d, i); } @Test public void testGroupReadable() throws Exception { Image i; Experimenter e = loginNewUser(Permissions.COLLAB_READONLY); i = createImage(); assertCanReadImage(i); loginNewUserInOtherUsersGroup(e); assertCanReadImage(i); loginNewUser(); assertCannotReadImage(i); } @Test public void testGroupLeadersCanReadAllInGroup() throws Exception { Image i; // as non-PI create an image.. Experimenter e = loginNewUser(Permissions.PRIVATE); i = createImage(); assertCanReadImage(i); // others in group can't read loginNewUserInOtherUsersGroup(e); assertCannotReadImage(i); // but PI can Experimenter pi = loginNewUserInOtherUsersGroup(e); loginRootKeepGroup(); iAdmin.setGroupOwner(currentGroup(), pi); loginUserKeepGroup(pi); assertCanReadImage(i); } @Test(groups = "broken") /* not supported currently */ public void testUserCanHideFromSelf() throws Exception { Image i; // create an image with no permissions Permissions unreadable = new Permissions(Permissions.USER_IMMUTABLE) .revoke(Role.USER, Right.READ); loginNewUser(unreadable); i = createImage(); assertCannotReadImage(i); } @Test public void testFilterDoesntHinderOuterJoins() throws Exception { } @Test public void testWorldReadable() throws Exception { } @Test public void testStatefulServicesFollowSameContract() throws Exception { } @Test /* doesn't reproduce */ public void testTicket663() { Experimenter e = loginNewUser(Permissions.PRIVATE); Project p = new Project("663"); Dataset d = new Dataset("663"); p.linkDataset(d); iUpdate.saveObject(p); long uid = iAdmin.getEventContext().getCurrentUserId(); ome.parameters.Filter filter = new ome.parameters.Filter().owner(uid); ome.parameters.Parameters params = new ome.parameters.Parameters(filter); findAllProjects(params); loginUserInNewGroup(e); findAllProjects(params); } private void findAllProjects(ome.parameters.Parameters params) { iQuery.findAllByQuery("select p from Project p" + " left outer join fetch p.datasetLinks l"+ " left outer join fetch l.child d", params); } @Test public void testTicket1798() throws Exception { Experimenter e = loginNewUser(); // Create an annotation like a user photo in #1798 long uid = iAdmin.getEventContext().getCurrentUserId(); FileAnnotation fa = new FileAnnotation(); ExperimenterAnnotationLink link = new ExperimenterAnnotationLink(); link.link(new Experimenter(uid, false), fa); iUpdate.saveObject(link); loadUserFileAnnotations(uid); // Now login to another group and see what happens loginUserInNewGroup(e); loadUserFileAnnotations(uid); } private void loadUserFileAnnotations(long uid) { Map<Long, Set<Annotation>> map = iMetadata.loadAnnotations( Experimenter.class, java.util.Collections.singleton(uid), Collections.singleton("FileAnnotation"), null, null); } // ~ Helpers // ========================================================================= private Image createImage() { Image img = new Image(); img.setName(ticket117 + ":" + UUID.randomUUID().toString()); return createObject(img); } private Dataset createDataset() { Dataset ds = new Dataset(); ds.setName(ticket117 + ":" + UUID.randomUUID().toString()); return createObject(ds); } private <T extends IObject> T createObject(T obj) { obj = factory.getUpdateService().saveAndReturnObject(obj); return obj; } private <T extends IObject> void assertCannotReadImage(T... ts) { T test; for (T t : ts) { test = getAsString(t); assertNull(t + "==null", test); test = getByCriteria(t); assertNull(t + "==null", test); } } private <T extends IObject> void assertCanReadImage(T... ts) { assertCanReadImage(iQuery, ts); } private <T extends IObject> void assertCanReadImage(IQuery q, T... ts) { T test; for (T t : ts) { test = getAsString(q, t); assertNotNull(t + "!=null", test); test = getByCriteria(q, t); assertNotNull(t + "!=null", test); } } private <T extends IObject> T getAsString(IQuery q, T obj) { return (T) iQuery.findByString(obj.getClass(), "name", ByNameQuery .name(obj)); } private <T extends IObject> T getByCriteria(IQuery q, T obj) { return (T) iQuery.execute(new ByNameQuery(obj)); } private <T extends IObject> T getAsString(T obj) { return getAsString(iQuery, obj); } private <T extends IObject> T getByCriteria(T obj) { return getByCriteria(iQuery, obj); } } class ByNameQuery extends Query { static Definitions defs = new Definitions(new QueryParameterDef("name", String.class, false)); Object obj; public <T extends IObject> ByNameQuery(T obj) { super(defs, new Parameters(new Filter().unique()).addString("name", name(obj))); this.obj = obj; } @Override protected void buildQuery(Session session) throws HibernateException, SQLException { Criteria c = session.createCriteria(obj.getClass()); c.add(Restrictions.eq("name", value("name"))); setCriteria(c); } static String name(Object object) { try { Field f = object.getClass().getDeclaredField("name"); f.setAccessible(true); return (String) f.get(object); } catch (Exception e) { throw new RuntimeException(e); } } }