/* * Copyright 2012-2013, CMM, University of Queensland. * * This file is part of Eccles. * * Eccles 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 3 of the License, or * (at your option) any later version. * * Eccles 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 Eccles. If not, see <http://www.gnu.org/licenses/>. */ package au.edu.uq.cmm.eccles; import java.io.FileInputStream; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.TypedQuery; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import au.edu.uq.cmm.aclslib.authenticator.AclsLoginDetails; import au.edu.uq.cmm.aclslib.authenticator.Authenticator; import au.edu.uq.cmm.aclslib.config.FacilityConfig; import au.edu.uq.cmm.aclslib.config.FacilityMapper; import au.edu.uq.cmm.aclslib.message.AclsException; import au.edu.uq.cmm.aclslib.proxy.AclsFacilityEvent; import au.edu.uq.cmm.aclslib.proxy.AclsFacilityEventListener; import au.edu.uq.cmm.aclslib.proxy.AclsLoginEvent; import au.edu.uq.cmm.aclslib.proxy.AclsLogoutEvent; import au.edu.uq.cmm.aclslib.proxy.AclsPasswordAcceptedEvent; import au.edu.uq.cmm.aclslib.proxy.AclsProxy; public class Eccles implements AclsFacilityEventListener, Authenticator { private static final Logger LOG = LoggerFactory.getLogger(Eccles.class); private AclsProxy proxy; private EntityManagerFactory emf; private SessionDetailMapper userDetailsMapper; private UserDetailsManager userDetailsManager; private EcclesProxyConfiguration config; /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { Properties properties = null; if (args.length > 0) { properties = new Properties(); try { properties.load(new FileInputStream(args[0])); } catch (IOException ex) { System.err.println(ex.getMessage()); System.exit(1); } } LOG.info("Hallo ... I'm the famous Eccles!"); try { new Eccles().run(properties); } catch (Throwable ex) { LOG.error("Some rotten swine has deaded me!", ex); } // (Wrong character, but who cares :-) ) LOG.info("Exits stage left on council dust cart. Pieew!!"); } private void run(Properties properties) throws InterruptedException { emf = properties == null ? Persistence.createEntityManagerFactory("au.edu.uq.cmm.paul") : Persistence.createEntityManagerFactory("au.edu.uq.cmm.paul", properties); config = EcclesProxyConfiguration.load(emf); FacilityMapper mapper = new EcclesFacilityMapper(config, emf); userDetailsMapper = new DefaultSessionDetailsMapper(); userDetailsManager = new EcclesUserDetailsManager(emf, config.getFallbackMode()); proxy = new AclsProxy(config, 0, mapper, config.getFallbackMode() == EcclesFallbackMode.NO_FALLBACK ? null : this); proxy.addListener(this); Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { LOG.info("Ok. I'll be off then"); proxy.startShutdown(); try { proxy.awaitShutdown(); } catch (InterruptedException ex) { LOG.error("Shutdown interrupted ...", ex); } LOG.info("Bye"); } })); proxy.startup(); Object lock = new Object(); synchronized (lock) { try { lock.wait(); } catch (InterruptedException ex) { LOG.error("Interrupted ...", ex); } } } public void eventOccurred(AclsFacilityEvent event) { LOG.debug("Processing event " + event); EntityManager em = emf.createEntityManager(); try { em.getTransaction().begin(); String facilityName = event.getFacilityName(); if (event instanceof AclsLoginEvent) { processLoginEvent((AclsLoginEvent) event, em, facilityName); } else if (event instanceof AclsLogoutEvent) { processLogoutEvent((AclsLogoutEvent) event, em, facilityName); } else { processPasswordAcceptedEvent( (AclsPasswordAcceptedEvent) event, em, facilityName); } em.getTransaction().commit(); } catch (InvalidSessionException ex) { LOG.error("Bad session information - ignoring facility event", ex); } finally { em.close(); } LOG.debug("Finished processing event " + event); } @Override public AclsLoginDetails authenticate( String userName, String password, FacilityConfig facility) throws AclsException { return userDetailsManager.authenticate(userName, password, facility); } private void processPasswordAcceptedEvent(AclsPasswordAcceptedEvent event, EntityManager em, String facilityName) throws InvalidSessionException { String userName = userDetailsMapper.mapToUserName(event.getUserName()); String email = userDetailsMapper.mapToEmailAddress(event.getUserName()); if (!event.getLoginDetails().isCached()) { userDetailsManager.refreshUserDetails( em, userName, email, event.getLoginDetails()); } } private void processLogoutEvent(AclsLogoutEvent event, EntityManager em, String facilityName) throws InvalidSessionException { FacilitySession session; String userName = userDetailsMapper.mapToUserName(event.getUserName()); String account = userDetailsMapper.mapToAccount(event.getAccount()); TypedQuery<FacilitySession> query = em.createQuery( "from FacilitySession f where f.facilityName = :facilityName " + "order by f.loginTime desc", FacilitySession.class); query.setParameter("facilityName", facilityName); query.setMaxResults(1); List<FacilitySession> sessions = query.getResultList(); if (sessions.isEmpty()) { throw new InvalidSessionException( "No sessions for facility " + facilityName); } session = sessions.get(0); if (session.getLogoutTime() != null) { throw new InvalidSessionException( "No current session for facility " + facilityName); } else if (!session.getUserName().equals(userName) || !session.getAccount().equals(account)) { throw new InvalidSessionException( "Inconsistent session user or account name for facility " + facilityName); } session.setLogoutTime(new Date()); } private void processLoginEvent(AclsLoginEvent event, EntityManager em, String facilityName) throws InvalidSessionException { FacilitySession session; String userName = userDetailsMapper.mapToUserName(event.getUserName()); String account = userDetailsMapper.mapToAccount(event.getAccount()); String email = userDetailsMapper.mapToEmailAddress(event.getUserName()); session = new FacilitySession( userName, account, facilityName, email, new Date()); em.persist(session); } }