/* * Copyright 2010 - 2014 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.services.ldap; import java.io.File; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import ome.api.local.LocalQuery; import ome.api.local.LocalUpdate; import ome.conditions.SecurityViolation; import ome.logic.LdapImpl; import ome.model.meta.Experimenter; import ome.model.meta.Session; import ome.security.auth.LdapConfig; import ome.security.auth.LdapPasswordProvider; import ome.security.auth.PasswordUtil; import ome.security.auth.RoleProvider; import ome.services.sessions.SessionManager; import ome.services.util.Executor; import ome.services.util.Executor.Work; import ome.system.EventContext; import ome.system.OmeroContext; import ome.system.Principal; import ome.system.Roles; import ome.system.ServiceFactory; import ome.tools.spring.InternalServiceFactory; import ome.util.SqlAction; import org.springframework.aop.target.HotSwappableTargetSource; import org.springframework.beans.BeansException; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.transaction.annotation.Transactional; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * Extends {@link LdapTest} to use a real DB. */ @Test(groups = "integration") public class LdapIntegrationTest extends LdapTest { Object old; OmeroContext mCtx; HotSwappableTargetSource hsts; SessionManager sessionManager; Executor executor; Principal p; @BeforeClass public void swap() { mCtx = OmeroContext.getManagedServerContext(); hsts = (HotSwappableTargetSource) mCtx.getBean("contextSourceSwapper"); old = hsts.getTarget(); sessionManager = (SessionManager) mCtx.getBean("sessionManager"); executor = (Executor) mCtx.getBean("executor"); } RoleProvider provider() { return (RoleProvider) mCtx.getBean("roleProvider"); } RoleProvider nonLdapProvider() { return (RoleProvider) mCtx.getBean("simpleRoleProvider"); } @BeforeMethod public void login() { p = newSession(null, "root", "system", null); } public Principal newSession(final Fixture fixture, final String username, final String group, final String password) { if (fixture != null && password != null) { // Will cause synchronization. Boolean check = (Boolean) executor.execute(p, new Executor.SimpleWork(this, "newSession") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return fixture.provider.checkPassword(username, password, true); } }); if (check != null && Boolean.FALSE.equals(check.booleanValue())) { throw new SecurityViolation("false returned."); } } Principal tmp = new Principal(username, group, "Test"); Session s = sessionManager.createWithAgent(tmp, "AbstractManagedContext", "127.0.0.1"); return new Principal(s.getUuid(), group, "Test"); } @AfterMethod public void logout() { sessionManager.closeAll(); } @Override protected Fixture createFixture(File ctxFile) throws Exception { Fixture fixture = new Fixture() { @Override public void createUserWithGroup(final LdapTest t, String dn, final String group) { executor.execute(p, new Executor.SimpleWork(this, "createUserWithGroup") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { ((LdapIntegrationTest) t).provider().createGroup(group, null, false); return null; } }); } @Override public Experimenter createUser(final String user) { executor.execute(p, new Executor.SimpleWork(this, "renameUser") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { Experimenter exp = null; try { exp = sf.getAdminService() .lookupExperimenter(user); } catch (Exception e) { // good } if (exp != null) { exp.setOmeName(UUID.randomUUID().toString()); sf.getAdminService() .updateExperimenter(exp); } return null; } }); return (Experimenter) executor.execute(p, new Executor.SimpleWork(this, "createUser") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return ldap.createUser(user); } }); } @Override public Experimenter createUser(final String user, final String password, final boolean checkPassword) { // To keep things simple, if a user already exists, // it gets renamed. Otherwise, it would be necessary to generate // the ldif on every execution. executor.execute(p, new Executor.SimpleWork(this, "renameUser") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { Experimenter exp = null; try { exp = sf.getAdminService() .lookupExperimenter(user); } catch (Exception e) { // good } if (exp != null) { exp.setOmeName(UUID.randomUUID().toString()); sf.getAdminService() .updateExperimenter(exp); } return null; } }); return (Experimenter) executor.execute(p, new Executor.SimpleWork(this, "createUser") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return ldap.createUser(user, "password", checkPassword); } }); } @Override public EventContext login(String username, String group, String password) { Principal user = newSession(this, username, group, password); EventContext ec = (EventContext) executor.execute(user, new Executor.SimpleWork(this, "simpleCall") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return sf.getAdminService().getEventContext(); } }); return ec; } @Override public Experimenter findExperimenter(final String username) { return (Experimenter) executor.execute(p, new Executor.SimpleWork(this, "findExperimenter") { @Transactional(readOnly = true) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return sf.getAdminService().lookupExperimenter( username); } }); } @Override public void setDN(final Long experimenterID, final String dn) { executor.execute(p, new Executor.SimpleWork(this, "setDN") { @Transactional(readOnly = false) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { ldap.setDN(experimenterID, dn); return null; } }); } @Override public List<Experimenter> discover() { return (List<Experimenter>) executor.execute(p, new Executor.SimpleWork(this, "discover") { @Transactional(readOnly = true) public Object doWork(org.hibernate.Session session, ServiceFactory sf) { return sf.getLdapService().discover(); } }); } @Override public Object execute(Work work) { return executor.execute(p, work); } }; fixture.ctx = new FileSystemXmlApplicationContext("file:" + ctxFile.getAbsolutePath()); fixture.config = (LdapConfig) fixture.ctx.getBean("config"); Map<String, LdapContextSource> sources = fixture.ctx .getBeansOfType(LdapContextSource.class); LdapContextSource source = sources.values().iterator().next(); String[] urls = source.getUrls(); assertEquals(1, urls.length); hsts.swap(source); fixture.applicationContext = this.mCtx; fixture.template = (LdapTemplate) mCtx.getBean("ldapTemplate"); fixture.template.setContextSource(source); try { fixture.ignoreCaseLookup = fixture.ctx.getBean("testIgnoreCase", Boolean.class); fixture.applicationContext.getBean("atomicIgnoreCase", AtomicBoolean.class).set(fixture.ignoreCaseLookup); } catch (BeansException be) { // skip this fixture } InternalServiceFactory isf = new InternalServiceFactory(mCtx); SqlAction sql = (SqlAction) mCtx.getBean("simpleSqlAction"); fixture.ldap = new LdapImpl(source, fixture.template, new Roles(), fixture.config, provider(), sql); fixture.ldap.setQueryService((LocalQuery) isf.getQueryService()); fixture.ldap.setUpdateService((LocalUpdate) isf.getUpdateService()); fixture.provider = new LdapPasswordProvider(new PasswordUtil(sql), fixture.ldap); fixture.provider.setApplicationContext(mCtx); return fixture; } @AfterClass public void unswap() { if (old != null && mCtx != null) { hsts.swap(old); } } }