/* * Copyright (C) 2012 Jan Pokorsky * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.common.user; import cz.cas.lib.proarc.common.dao.DaoFactory; import cz.cas.lib.proarc.common.dao.GroupDao; import cz.cas.lib.proarc.common.dao.Transaction; import cz.cas.lib.proarc.common.dao.UserDao; import cz.cas.lib.proarc.common.dao.empiredb.SqlTransaction; import cz.cas.lib.proarc.common.fedora.FedoraTransaction; import cz.cas.lib.proarc.common.fedora.RemoteStorage; import cz.cas.lib.proarc.common.sql.DbUtils; import java.io.File; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.io.FileUtils; /** * Manages user stuff in RDBMS and the Fedora storage. * * @author Jan Pokorsky */ final class UserManagerSql implements UserManager { private static final Logger LOG = Logger.getLogger(UserManagerSql.class.getName()); private final DataSource source; private final File defaultHome; private final GroupSqlStorage groupStorage; private final PermissionSqlStorage permissionStorage; private final RemoteStorage remoteStorage; private final DaoFactory daos; public UserManagerSql(DataSource source, File defaultHome, RemoteStorage remoteStorage, DaoFactory daos) { this.source = source; this.defaultHome = defaultHome; groupStorage = new GroupSqlStorage(source); permissionStorage = new PermissionSqlStorage(source); this.remoteStorage = remoteStorage; this.daos = daos; } @Override public UserProfile authenticate(String userName, String passwd) { if (userName == null || passwd == null) { return null; } String digist = UserUtil.getDigist(passwd); Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { List<UserProfile> result = users.find(userName, digist, null, null); return result.isEmpty() ? null : filter(result.get(0)); } finally { tx.close(); } } @Override public UserProfile find(String userName) throws IllegalArgumentException { if (userName == null) { return null; } Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { List<UserProfile> result = users.find(userName, null, null, null); return result.isEmpty() ? null : filter(result.get(0)); } finally { tx.close(); } } @Override public UserProfile find(String remoteName, String remoteType) { if (remoteName == null || remoteType == null) { return null; } Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { List<UserProfile> result = users.find(null, null, remoteName, remoteType); return result.isEmpty() ? null : filter(result.get(0)); } finally { tx.close(); } } @Override public UserProfile find(int userId) throws IllegalArgumentException { Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { return filter(users.find(userId)); } finally { tx.close(); } } @Override public List<UserProfile> findAll() { Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { return filter(users.find(null, null, null, null)); } finally { tx.close(); } } @Override public UserProfile add(UserProfile profile, List<Group> groups, String owner, String log) { if (profile == null) { throw new NullPointerException(); } profile.validateAsNew(); File userHome = null; FedoraTransaction ftx = new FedoraTransaction(remoteStorage); Transaction tx = daos.createTransaction(); UserDao userDao = daos.createUser(); GroupDao groupDao = daos.createUserGroup(); FedoraUserDao fedoraUsers = new FedoraUserDao(); FedoraGroupDao fedoraGroups = new FedoraGroupDao(); userDao.setTransaction(tx); groupDao.setTransaction(tx); fedoraUsers.setTransaction(ftx); fedoraGroups.setTransaction(ftx); try { // fedora fedoraUsers.add(profile, owner, log); Group userGroup = createUserGroup(profile); fedoraGroups.addNewGroup(userGroup, owner, log); final List<Group> membership = new ArrayList<Group>(groups.size() + 1); membership.addAll(groups); membership.add(userGroup); fedoraUsers.setMembership(profile, membership, log); // rdbms groupDao.update(userGroup); userHome = UserUtil.createUserHome(profile.getUserName(), null, defaultHome); profile.setUserHome(UserUtil.toUri(userHome)); profile.setUserGroup(userGroup.getId()); userDao.update(profile); // sql membership groupStorage.addMembership(((SqlTransaction) tx).getConnection(), profile.getId(), membership); // filesystem UserUtil.createUserSubfolders(userHome); userHome = null; tx.commit(); ftx.commit(); return filter(profile); } catch (Throwable ex) { ftx.rollback(); tx.rollback(); throw new IllegalStateException(filter(profile).toString(), ex); } finally { if (userHome != null) { FileUtils.deleteQuietly(userHome); } ftx.close(); tx.close(); } } @Override public void update(UserProfile profile, String owner, String log) { Transaction tx = daos.createTransaction(); UserDao users = daos.createUser(); users.setTransaction(tx); try { if (profile.getUserPassword() != null) { profile.setUserPasswordDigest(UserUtil.getDigist(profile.getUserPassword())); } users.update(profile); filter(profile); tx.commit(); } catch (Throwable ex) { tx.rollback(); throw new IllegalStateException(String.valueOf(filter(profile)), ex); } finally { tx.close(); } } @Override public Group addGroup(Group group, List<Permission> permissions, String owner, String log) { if (!UserUtil.isValidGroupPid(group.getName())) { throw new IllegalArgumentException("groupName: " + group.getName()); } Transaction tx = daos.createTransaction(); GroupDao groupDao = daos.createUserGroup(); groupDao.setTransaction(tx); FedoraTransaction ftx = new FedoraTransaction(remoteStorage); FedoraGroupDao fedoraGroups = new FedoraGroupDao(); fedoraGroups.setTransaction(ftx); try { fedoraGroups.addGroup(group, owner, log); groupDao.update(group); if (!permissions.isEmpty()) { permissionStorage.set(((SqlTransaction) tx).getConnection(), group.getId(), permissions.toArray(new Permission[permissions.size()])); } tx.commit(); ftx.commit(); return group; } catch (Throwable ex) { ftx.rollback(); tx.rollback(); throw new IllegalStateException(String.valueOf(group), ex); } finally { ftx.close(); tx.close(); } } @Override public List<Group> findGroups() { Transaction tx = daos.createTransaction(); GroupDao groupDao = daos.createUserGroup(); groupDao.setTransaction(tx); try { return groupDao.find(null, null, null, null); } finally { tx.close(); } } @Override public Group findGroup(int groupId) { Transaction tx = daos.createTransaction(); GroupDao groupDao = daos.createUserGroup(); groupDao.setTransaction(tx); try { return groupDao.find(groupId); } finally { tx.close(); } } @Override public Group findRemoteGroup(String remoteName, String remoteType) { Transaction tx = daos.createTransaction(); GroupDao groupDao = daos.createUserGroup(); groupDao.setTransaction(tx); try { List<Group> groups = groupDao.find(null, null, remoteName, remoteType); return groups.isEmpty() ? null : groups.get(0); } finally { tx.close(); } } @Override public void setUserGroups(UserProfile user, List<Group> groups, String owner, String log) { try { FedoraTransaction ftx = new FedoraTransaction(remoteStorage); FedoraUserDao fedoraUsers = new FedoraUserDao(); fedoraUsers.setTransaction(ftx); Connection c = source.getConnection(); boolean rollback = true; try { c.setAutoCommit(false); groupStorage.removeMembership(c, user.getId()); if (!groups.isEmpty()) { groupStorage.addMembership(c, user.getId(), groups); } fedoraUsers.setMembership(user, groups, log); c.commit(); ftx.commit(); rollback = false; } finally { ftx.close(); DbUtils.close(c, rollback); } } catch (Exception ex) { throw new IllegalStateException(ex); } } @Override public List<Group> findUserGroups(int userId) { try { Connection c = getConnection(); try { c.setAutoCommit(true); return groupStorage.findUserGroups(c, userId); } finally { DbUtils.close(c); } } catch (SQLException ex) { throw new IllegalStateException(ex); } } @Override public Set<Permission> findUserPermissions(int userId) { try { Connection c = getConnection(); try { c.setAutoCommit(true); return permissionStorage.find(c, userId); } finally { DbUtils.close(c); } } catch (SQLException ex) { throw new IllegalStateException(ex); } } @Override public void setPermissions(int groupId, Permission... permissions) { if (permissions == null || permissions.length == 0) { throw new IllegalStateException("permissions"); } try { Connection c = source.getConnection(); boolean rollback = true; try { c.setAutoCommit(false); permissionStorage.set(c, groupId, permissions); c.commit(); rollback = false; } finally { DbUtils.close(c, rollback); } } catch (SQLException ex) { throw new IllegalStateException(ex); } } @Override public void removePermissions(int groupId) { try { Connection c = source.getConnection(); boolean rollback = true; try { c.setAutoCommit(false); permissionStorage.remove(c, groupId); c.commit(); rollback = false; } finally { DbUtils.close(c, rollback); } } catch (SQLException ex) { throw new IllegalStateException(ex); } } private static Group createUserGroup(UserProfile user) { return Group.create(user.getUserName(), null); } private static UserProfile filter(UserProfile user) { if (user != null) { user.setUserPassword(null); user.setUserPasswordDigest(null); } return user; } private static List<UserProfile> filter(List<UserProfile> users) { for (UserProfile user : users) { filter(user); } return users; } private Connection getConnection() throws SQLException { return source.getConnection(); } }