/* ******************************************************************** Licensed to Jasig under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Jasig licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.bedework.calsvc; import org.bedework.access.Access; import org.bedework.access.PrivilegeDefs; import org.bedework.access.WhoDefs; import org.bedework.calfacade.BwCalendar; import org.bedework.calfacade.BwGroup; import org.bedework.calfacade.BwPrincipal; import org.bedework.calfacade.BwUser; import org.bedework.calfacade.DirectoryInfo; import org.bedework.calfacade.exc.CalFacadeException; import org.bedework.calfacade.svc.BwPreferences; import org.bedework.calfacade.svc.BwView; import org.bedework.calsvci.CalSvcI; import org.bedework.calsvci.UsersI; import org.bedework.sysevents.events.SysEvent; import org.bedework.util.misc.Util; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.bedework.calfacade.configs.BasicSystemProperties.colPathEndsWithSlash; /** This acts as an interface to the database for user objects. * * @author Mike Douglass douglm - rpi.edu */ class Users extends CalSvcDb implements UsersI { /* The account that owns public entities */ private String publicUserAccount; private BwPrincipal publicUser; Users(final CalSvc svci) throws CalFacadeException { super(svci); } @Override public BwPrincipal getUser(final String account) throws CalFacadeException { if (account == null) { return null; } setRoots(getSvc()); final String href = getSvc().getDirectories().makePrincipalUri(account, WhoDefs.whoTypeUser); return getPrincipal(href); } @Override public BwPrincipal getAlways(final String account) throws CalFacadeException { if (account == null) { // Return guest user return BwPrincipal.makeUserPrincipal(); } final BwPrincipal u = getUser(account); if (u == null) { add(account); } return getUser(account); } /* Make this session specific for the moment. We could make it static possibly * Also flush every few minutes */ private final Map<String, BwPrincipal> principalMap = new HashMap<>(); private long lastFlush = System.currentTimeMillis(); private static final long flushInt = 1000 * 30 * 5; // 5 minutes private static String principalRoot; private static String userPrincipalRoot; private static String groupPrincipalRoot; //private static int principalRootLen; // private static int userPrincipalRootLen; private static int groupPrincipalRootLen; private static void setRoots(final CalSvcI svc) throws CalFacadeException { if (principalRoot != null) { return; } final DirectoryInfo di = svc.getDirectories().getDirectoryInfo(); principalRoot = di.getPrincipalRoot(); userPrincipalRoot = di.getUserPrincipalRoot(); groupPrincipalRoot = di.getGroupPrincipalRoot(); //principalRootLen = principalRoot.length(); //userPrincipalRootLen = userPrincipalRoot.length(); groupPrincipalRootLen = groupPrincipalRoot.length(); } private BwPrincipal mappedPrincipal(final String val) { final long now = System.currentTimeMillis(); if ((now - lastFlush) > flushInt) { principalMap.clear(); lastFlush = now; return null; } return principalMap.get(val); } @Override public BwPrincipal getPrincipal(final String val) throws CalFacadeException { if (val == null) { return null; } BwPrincipal p = mappedPrincipal(val); if (p != null) { return p; } setRoots(getSvc()); if (!val.startsWith(principalRoot)) { return null; } if (val.startsWith(userPrincipalRoot)) { final BwPrincipal u = getSvc().getPrincipal(val); if (u != null) { principalMap.put(val, u); } return u; } if (val.startsWith(groupPrincipalRoot)) { BwGroup g = getSvc().getDirectories().findGroup(val.substring(groupPrincipalRootLen)); if (g != null) { principalMap.put(val, g); } return g; } return null; } @Override public void add(final String val) throws CalFacadeException { getSvc().addUser(val); } BwPrincipal initUserObject(final String val) throws CalFacadeException { String account = val; if (getSvc().getDirectories().isPrincipal(val)) { account = getSvc().getDirectories().accountFromPrincipal(val); } if (account == null) { throw new CalFacadeException("Bad user account " + val); } setRoots(getSvc()); final BwPrincipal user = BwPrincipal.makeUserPrincipal(); user.setAccount(account); user.setCategoryAccess(Access.getDefaultPersonalAccess()); user.setLocationAccess(Access.getDefaultPersonalAccess()); user.setContactAccess(Access.getDefaultPersonalAccess()); ((BwUser)user).setQuota(getSvc().getAuthProperties().getDefaultUserQuota()); user.setPrincipalRef(Util.buildPath(colPathEndsWithSlash, userPrincipalRoot, "/", account)); return user; } void createUser(final String val) throws CalFacadeException { final BwPrincipal user = initUserObject(val); setRoots(getSvc()); getCal().saveOrUpdate(user); getSvc().initPrincipal(user); initPrincipal(user, getSvc()); getCal().getSpecialCalendar(user, BwCalendar.calTypeInbox, true, PrivilegeDefs.privAny); getCal().getSpecialCalendar(user, BwCalendar.calTypePendingInbox, true, PrivilegeDefs.privAny); getCal().getSpecialCalendar(user, BwCalendar.calTypeOutbox, true, PrivilegeDefs.privAny); getCal().getSpecialCalendar(user, BwCalendar.calTypeNotifications, true, PrivilegeDefs.privAny); getCal().getSpecialCalendar(user, BwCalendar.calTypePoll, true, PrivilegeDefs.privAny); getCal().getSpecialCalendar(user, BwCalendar.calTypeTasks, true, PrivilegeDefs.privAny); getSvc().postNotification(SysEvent.makePrincipalEvent(SysEvent.SysCode.NEW_USER, user, 0)); } @Override public void update(final BwPrincipal principal) throws CalFacadeException { getCal().saveOrUpdate(principal); } @Override public void remove(final BwPrincipal pr) throws CalFacadeException { final String userRoot = getSvc().getPrincipalInfo().getCalendarHomePath(pr); /* views */ final Collection<BwView> views = getSvc().getViewsHandler().getAll(pr); for (final BwView view: views) { getSvc().getViewsHandler().remove(view); } /* Set default calendar to null so we don't get blocked. */ final BwPreferences prefs = getSvc().getPrefsHandler().get(pr); if (prefs != null) { prefs.setDefaultCalendarPath(null); getSvc().getPrefsHandler().update(prefs); } /* collections and user home */ final BwCalendar home = getSvc().getCalendarsHandler().get(userRoot); if (home != null) { ((Calendars)getCols()).delete(home, true, true, false, true); } /* Remove preferences */ getSvc().getPrefsHandler().delete(prefs); getCal().delete(pr); } @Override public void logon(final BwPrincipal val) throws CalFacadeException { //final Timestamp now = new Timestamp(System.currentTimeMillis()); /* TODO - add unversioned login table this can cause stale state exceptions - val.setLogon(now); val.setLastAccess(now); getCal().saveOrUpdate(val); */ /* Ensure we have a polls collection. I think this was a short-term fix that hung around. It's not a good idea. Makes session start inefficient. getSvc().getCal().getSpecialCalendar(val, BwCalendar.calTypePoll, true, PrivilegeDefs.privAny); */ } /* public void deleteUser(BwUser user) throws CalFacadeException { checkOpen(); throw new CalFacadeException("Unimplemented"); }*/ /* (non-Javadoc) * @see org.bedework.calsvci.UsersI#initPrincipal(org.bedework.calfacade.BwPrincipal) */ @Override public void initPrincipal(final BwPrincipal principal) throws CalFacadeException { initPrincipal(principal, getSvc()); } private void initPrincipal(final BwPrincipal principal, final CalSvc svc) throws CalFacadeException { // Add preferences final BwPreferences prefs = new BwPreferences(); prefs.setOwnerHref(principal.getPrincipalRef()); prefs.setDefaultCalendarPath( Util.buildPath(colPathEndsWithSlash, getSvc().getPrincipalInfo().getCalendarHomePath(principal), "/", getBasicSyspars().getUserDefaultCalendar())); // Add a default view for the calendar home final BwView view = new BwView(); view.setName(getAuthpars().getDefaultUserViewName()); // Add default subscription to the user root. view.addCollectionPath(svc.getPrincipalInfo().getCalendarHomePath(principal)); prefs.addView(view); prefs.setPreferredView(view.getName()); prefs.setPreferredViewPeriod("week"); prefs.setHour24(getAuthpars().getDefaultUserHour24()); prefs.setScheduleAutoRespond(principal.getKind() == WhoDefs.whoTypeResource); svc.getPrefsHandler().update(prefs); } @Override public BwPrincipal getPublicUser() throws CalFacadeException { if (publicUser == null) { publicUser = getUser(getPublicUserAccount()); } if (publicUser == null) { throw new CalFacadeException("No guest user proxy account - expected " + publicUserAccount); } return publicUser; } @Override public List<String> getPrincipalHrefs(final int start, final int count) throws CalFacadeException { return getCal().getPrincipalHrefs(start, count); } /* ==================================================================== * Private methods * ==================================================================== */ private String getPublicUserAccount() throws CalFacadeException { if (publicUserAccount == null) { publicUserAccount = getBasicSyspars().getPublicUser(); } return publicUserAccount; } }