/******************************************************************************* * Copyright (c) 2008-2011 Chair for Applied Software Engineering, * Technische Universitaet Muenchen. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: ******************************************************************************/ package org.eclipse.emf.emfstore.server.accesscontrol; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.emfstore.server.ServerConfiguration; import org.eclipse.emf.emfstore.server.accesscontrol.PermissionProvider.InternalPermission; import org.eclipse.emf.emfstore.server.accesscontrol.authentication.AbstractAuthenticationControl; import org.eclipse.emf.emfstore.server.accesscontrol.authentication.factory.AuthenticationControlFactory; import org.eclipse.emf.emfstore.server.accesscontrol.authentication.factory.AuthenticationControlFactoryImpl; import org.eclipse.emf.emfstore.server.core.MonitorProvider; import org.eclipse.emf.emfstore.server.exceptions.AccessControlException; import org.eclipse.emf.emfstore.server.exceptions.FatalEmfStoreException; import org.eclipse.emf.emfstore.server.exceptions.SessionTimedOutException; import org.eclipse.emf.emfstore.server.model.ClientVersionInfo; import org.eclipse.emf.emfstore.server.model.ProjectId; import org.eclipse.emf.emfstore.server.model.ServerSpace; import org.eclipse.emf.emfstore.server.model.SessionId; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACGroup; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACOrgUnit; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACOrgUnitId; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACUser; import org.eclipse.emf.emfstore.server.model.accesscontrol.PermissionType; import org.eclipse.emf.emfstore.server.model.accesscontrol.RoleAssignment; import org.eclipse.emf.emfstore.server.model.operation.Operation; /** * A simple implementation of Authentication and Authorization Control. * * @author koegel * @author wesendonk */ public class AccessControlImpl implements AuthenticationControl, AuthorizationControl { private Map<SessionId, ACUserContainer> sessionUserMap; private ServerSpace serverSpace; private AbstractAuthenticationControl authenticationControl; private PermissionProvider permissionProvider; /** * Default constructor. * * @param serverSpace * the server space to work on * @throws FatalEmfStoreException * an exception */ public AccessControlImpl(ServerSpace serverSpace, PermissionProvider permissionProvider) throws FatalEmfStoreException { this.sessionUserMap = new HashMap<SessionId, ACUserContainer>(); this.serverSpace = serverSpace; this.permissionProvider = permissionProvider; authenticationControl = getAuthenticationFactory().createAuthenticationControl(); } private AuthenticationControlFactory getAuthenticationFactory() { IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor( "org.eclipse.emf.emfstore.server.authenticationfactory"); // get all providers from the extension points for (IConfigurationElement e : config) { try { Object o = e.createExecutableExtension("class"); if (o instanceof AuthenticationControlFactory) { return (AuthenticationControlFactory) o; } } catch (CoreException e1) { // fail silently // e1.printStackTrace(); } } // fallback in case that no factory was registered return new AuthenticationControlFactoryImpl(); } /** * {@inheritDoc} * * @see org.eclipse.emf.emfstore.server.accesscontrol.AuthenticationControl#logIn(java.lang.String, * java.lang.String) */ public SessionId logIn(String username, String password, ClientVersionInfo clientVersionInfo) throws AccessControlException { synchronized (MonitorProvider.getInstance().getMonitor("authentication")) { ACUser user = resolveUser(username); SessionId sessionId = authenticationControl.logIn(user.getName(), password, clientVersionInfo); sessionUserMap.put(sessionId, new ACUserContainer(user)); return sessionId; } } /** * {@inheritDoc} * * @see org.eclipse.emf.emfstore.server.accesscontrol.AuthenticationControl#logout(org.eclipse.emf.emfstore.server.model.SessionId) */ public void logout(SessionId sessionId) throws AccessControlException { synchronized (MonitorProvider.getInstance().getMonitor("authentication")) { if (sessionId == null) { throw new AccessControlException("SessionId is null."); } sessionUserMap.remove(sessionId); } } /** * Resolve a String to a user. * * @param username * @return the ACuser instance with the given name * @throws AccessControlException * if there is no such user */ private ACUser resolveUser(String username) throws AccessControlException { Boolean ignoreCase = Boolean.parseBoolean(ServerConfiguration.getProperties().getProperty( ServerConfiguration.AUTHENTICATION_MATCH_USERS_IGNORE_CASE, "false")); synchronized (MonitorProvider.getInstance().getMonitor()) { for (ACUser user : serverSpace.getUsers()) { if (ignoreCase) { if (user.getName().equalsIgnoreCase(username)) { return user; } } else { if (user.getName().equals(username)) { return user; } } } throw new AccessControlException(); } } /** * {@inheritDoc} * * @see org.eclipse.emf.emfstore.server.accesscontrol.AuthorizationControl#checkSession(org.eclipse.emf.emfstore.server.model.SessionId) */ public void checkSession(SessionId sessionId) throws AccessControlException { if (!sessionUserMap.containsKey(sessionId)) { throw new SessionTimedOutException("Session ID unkown."); } sessionUserMap.get(sessionId).checkLastActive(); } private ACUser getUser(ACOrgUnitId orgUnitId) throws AccessControlException { synchronized (MonitorProvider.getInstance().getMonitor()) { for (ACUser user : serverSpace.getUsers()) { if (user.getId().equals(orgUnitId)) { return user; } } throw new AccessControlException("Given User doesn't exist."); } } public PermissionProvider getPermissionProvider() { return permissionProvider; } /** * {@inheritDoc} */ public ACUser resolveUser(SessionId sessionId) throws AccessControlException { checkSession(sessionId); return sessionUserMap.get(sessionId).getRawUser(); } /** * {@inheritDoc} */ public ACUser resolveUser(ACOrgUnitId id) throws AccessControlException { return getUser(id); } // extract to normal class /** * @author wesendonk */ private class ACUserContainer { private ACUser acUser; // private long firstActive; private long lastActive; public ACUserContainer(ACUser acUser) { this.acUser = acUser; // firstActive = System.currentTimeMillis(); active(); } /** * Get the ACUser. * * @return * @throws AccessControlException */ public ACUser getUser() { active(); return getRawUser(); } public ACUser getRawUser() { return acUser; } public void checkLastActive() throws AccessControlException { // OW finish implementing this method String property = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SESSION_TIMEOUT, ServerConfiguration.SESSION_TIMEOUT_DEFAULT); if (System.currentTimeMillis() - lastActive > Integer.parseInt(property) /* * || System.currentTimeMillis() - firstActive > * Integer.parseInt(property) */) { // OW: delete from map throw new SessionTimedOutException("Usersession timed out."); } } private void active() { lastActive = System.currentTimeMillis(); } } public void checkPermission(SessionId sessionId, InternalPermission permission) throws AccessControlException { Collection<InternalPermission> permissions = new ArrayList<InternalPermission>(); permissions.add(permission); checkPermissions(sessionId, permissions); } public void checkPermissions(SessionId sessionId, Collection<InternalPermission> permissions) throws AccessControlException { if (!hasPermissions(sessionId, permissions)) { List<Permission> missingPermissions = new ArrayList<Permission>(); for (InternalPermission permission : getMissingPermissions(sessionId, permissions)) { ProjectId projectId = permission.getProjectId(); missingPermissions.add(new Permission(permission.getType().getId(), projectId == null ? null : projectId.getId())); } throw new AccessControlException(missingPermissions.toArray(new Permission[0])); } } public boolean hasPermissions(SessionId sessionId, Collection<InternalPermission> permissions) throws AccessControlException { InternalPermission[] missingPermissions = getMissingPermissions(sessionId, permissions); if (missingPermissions.length == 0) { return true; } return false; } public InternalPermission[] getMissingPermissions(SessionId sessionId, Collection<InternalPermission> permissions) throws AccessControlException { checkSession(sessionId); ACUserContainer userContainer = sessionUserMap.get(sessionId); ACUser user = userContainer.getUser(); Set<InternalPermission> requiredPermissions = new HashSet<PermissionProvider.InternalPermission>(); requiredPermissions.addAll(permissions); for (InternalPermission permission : getPermissions(user)) { ProjectId projectId = permission.getProjectId(); Iterator<InternalPermission> iterator = requiredPermissions.iterator(); while (iterator.hasNext()) { InternalPermission requiredPermission = iterator.next(); if (requiredPermission.getType().equals(permission.getType()) && (projectId == null || projectId.equals(requiredPermission.getProjectId()))) { iterator.remove(); } } if (requiredPermissions.size() == 0) { return new InternalPermission[] {}; } } return requiredPermissions.toArray(new InternalPermission[0]); } private Set<InternalPermission> getPermissions(ACOrgUnit orgUnit) { Set<InternalPermission> permissions = new HashSet<InternalPermission>(); for (RoleAssignment assignment : orgUnit.getRoles()) { for (PermissionType permissionType : assignment.getRole().getPermissionTypes()) { permissions.add(new InternalPermission(permissionType, assignment.getProjectId())); } } for (ACGroup group : orgUnit.getGroups()) { permissions.addAll(getPermissions(group)); } return permissions; } public boolean hasPermissions(SessionId sessionId, Operation<?> operation) throws AccessControlException { return hasPermissions(sessionId, getPermissions(sessionId, operation)); } public Collection<InternalPermission> getPermissions(SessionId sessionId, Operation<?> op) throws AccessControlException { checkSession(sessionId); ACUserContainer userContainer = sessionUserMap.get(sessionId); if (userContainer == null) { throw new RuntimeException(); } ACUser user = userContainer.getUser(); return getPermissionProvider().getPermissions(op, user); } public void checkPermissions(SessionId sessionId, Operation<?> op) throws AccessControlException { checkPermissions(sessionId, getPermissions(sessionId, op)); } }