--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. 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
+ */
+
+package org.opendaylight.controller.usermanager.internal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.IConfigurationAware;
+import org.opendaylight.controller.containermanager.IContainerAuthorization;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.authorization.IResourceAuthorization;
+import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectWriter;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.usermanager.AuthResponse;
+import org.opendaylight.controller.usermanager.AuthorizationConfig;
+import org.opendaylight.controller.usermanager.IAAAProvider;
+import org.opendaylight.controller.usermanager.ISessionManager;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.ServerConfig;
+import org.opendaylight.controller.usermanager.UserConfig;
+import org.opendaylight.controller.usermanager.security.SessionManager;
+import org.opendaylight.controller.usermanager.security.UserSecurityContextRepository;
+import org.opendaylight.controller.usermanager.internal.AuthenticatedUser;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+/**
+ * The internal implementation of the User Manager.
+ */
+public class UserManagerImpl implements IUserManager, IObjectReader,
+ IConfigurationAware, ICacheUpdateAware<Long, String>, CommandProvider,
+ AuthenticationProvider {
+ private static final Logger logger = LoggerFactory
+ .getLogger(UserManagerImpl.class);
+ private static final String defaultAdmin = "admin";
+ private static final String defaultAdminPassword = "admin";
+ private static final String defaultAdminRole = UserLevel.NETWORKADMIN
+ .toString();
+ private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
+ private static final String SAVE = "save";
+ private static final String usersFileName = ROOT + "users.conf";
+ private static final String serversFileName = ROOT + "servers.conf";
+ private static final String authFileName = ROOT + "authorization.conf";
+ private ConcurrentMap<String, UserConfig> localUserConfigList;
+ private ConcurrentMap<String, ServerConfig> remoteServerConfigList;
+ // local authorization info for remotely authenticated users
+ private ConcurrentMap<String, AuthorizationConfig> authorizationConfList;
+ private ConcurrentMap<String, AuthenticatedUser> activeUsers;
+ private ConcurrentMap<String, IAAAProvider> authProviders;
+ private ConcurrentMap<Long, String> localUserListSaveConfigEvent,
+ remoteServerSaveConfigEvent, authorizationSaveConfigEvent;
+ private IClusterGlobalServices clusterGlobalService = null;
+ private SecurityContextRepository securityContextRepo = new UserSecurityContextRepository();
+ private IContainerAuthorization containerAuthorizationClient;
+ private Set<IResourceAuthorization> applicationAuthorizationClients;
+ private ISessionManager sessionMgr = new SessionManager();
+
+ public boolean addAAAProvider(IAAAProvider provider) {
+ if (provider == null || provider.getName() == null
+ || provider.getName().trim().isEmpty()) {
+ return false;
+ }
+ if (authProviders.get(provider.getName()) != null) {
+ return false;
+ }
+
+ authProviders.put(provider.getName(), provider);
+ return true;
+ }
+
+ public void removeAAAProvider(IAAAProvider provider) {
+ authProviders.remove(provider.getName());
+ }
+
+ public IAAAProvider getAAAProvider(String name) {
+ return authProviders.get(name);
+ }
+
+ @Override
+ public Set<String> getAAAProviderNames() {
+ return authProviders.keySet();
+ }
+
+ @SuppressWarnings("deprecation")
+ private void allocateCaches() {
+ this.applicationAuthorizationClients = Collections
+ .synchronizedSet(new HashSet<IResourceAuthorization>());
+ if (clusterGlobalService == null) {
+ logger.error("un-initialized clusterGlobalService, can't create cache");
+ return;
+ }
+
+ try {
+ clusterGlobalService.createCache("usermanager.localUserConfigList",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache(
+ "usermanager.remoteServerConfigList",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache(
+ "usermanager.authorizationConfList",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache("usermanager.activeUsers",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache(
+ "usermanager.localUserSaveConfigEvent",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache(
+ "usermanager.remoteServerSaveConfigEvent",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ clusterGlobalService.createCache(
+ "usermanager.authorizationSaveConfigEvent",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheConfigException cce) {
+ logger.error("Cache configuration invalid - check cache mode");
+ } catch (CacheExistException ce) {
+ logger.debug("Skipping cache creation as already present");
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "deprecation" })
+ private void retrieveCaches() {
+ if (clusterGlobalService == null) {
+ logger.error("un-initialized clusterService, can't retrieve cache");
+ return;
+ }
+
+ activeUsers = (ConcurrentMap<String, AuthenticatedUser>) clusterGlobalService
+ .getCache("usermanager.activeUsers");
+ if (activeUsers == null) {
+ logger.error("Failed to get cache for activeUsers");
+ }
+
+ localUserConfigList = (ConcurrentMap<String, UserConfig>) clusterGlobalService
+ .getCache("usermanager.localUserConfigList");
+ if (localUserConfigList == null) {
+ logger.error("Failed to get cache for localUserConfigList");
+ }
+
+ remoteServerConfigList = (ConcurrentMap<String, ServerConfig>) clusterGlobalService
+ .getCache("usermanager.remoteServerConfigList");
+ if (remoteServerConfigList == null) {
+ logger.error("Failed to get cache for remoteServerConfigList");
+ }
+
+ authorizationConfList = (ConcurrentMap<String, AuthorizationConfig>) clusterGlobalService
+ .getCache("usermanager.authorizationConfList");
+ if (authorizationConfList == null) {
+ logger.error("Failed to get cache for authorizationConfList");
+ }
+
+ localUserListSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
+ .getCache("usermanager.localUserSaveConfigEvent");
+ if (localUserListSaveConfigEvent == null) {
+ logger.error("Failed to get cache for localUserSaveConfigEvent");
+ }
+
+ remoteServerSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
+ .getCache("usermanager.remoteServerSaveConfigEvent");
+ if (remoteServerSaveConfigEvent == null) {
+ logger.error("Failed to get cache for remoteServerSaveConfigEvent");
+ }
+
+ authorizationSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
+ .getCache("usermanager.authorizationSaveConfigEvent");
+ if (authorizationSaveConfigEvent == null) {
+ logger.error("Failed to get cache for authorizationSaveConfigEvent");
+ }
+ }
+
+ private void loadConfigurations() {
+ // To encode and decode user and server configuration objects
+ loadSecurityKeys();
+
+ /*
+ * Do not load local startup file if we already got the configurations
+ * synced from another cluster node
+ */
+ if (localUserConfigList.isEmpty()) {
+ loadUserConfig();
+ }
+ if (remoteServerConfigList.isEmpty()) {
+ loadServerConfig();
+ }
+ if (authorizationConfList.isEmpty()) {
+ loadAuthConfig();
+ }
+ }
+
+ private void loadSecurityKeys() {
+
+ }
+
+ private void checkDefaultNetworkAdmin() {
+ // If startup config is not there, it's old or it was deleted,
+ // need to add Default Admin
+ if (!localUserConfigList.containsKey(defaultAdmin)) {
+ List<String> roles = new ArrayList<String>(1);
+ roles.add(defaultAdminRole);
+ localUserConfigList.put(defaultAdmin, new UserConfig(defaultAdmin,
+ defaultAdminPassword, roles));
+ }
+ }
+
+ @Override
+ public AuthResultEnum authenticate(String userName, String password) {
+ IAAAProvider aaaClient;
+ AuthResponse rcResponse = null;
+ AuthenticatedUser result;
+ boolean remotelyAuthenticated = false;
+ boolean authorizationInfoIsPresent = false;
+ boolean authorized = false;
+
+ /*
+ * Attempt remote authentication first if server is configured
+ */
+ for (ServerConfig aaaServer : remoteServerConfigList.values()) {
+ String protocol = aaaServer.getProtocol();
+ aaaClient = this.getAAAProvider(protocol);
+ if (aaaClient != null) {
+ rcResponse = aaaClient.authService(userName, password,
+ aaaServer.getAddress(), aaaServer.getSecret());
+ if (rcResponse.getStatus() == AuthResultEnum.AUTH_ACCEPT) {
+ logger.info(
+ "Remote Authentication Succeeded for User: \"{}\", by Server: {}",
+ userName, aaaServer.getAddress());
+ remotelyAuthenticated = true;
+ break;
+ } else if (rcResponse.getStatus() == AuthResultEnum.AUTH_REJECT) {
+ logger.info(
+ "Remote Authentication Rejected User: \"{}\", from Server: {}, Reason:{}",
+ new Object[] { userName, aaaServer.getAddress(),
+ rcResponse.getStatus().toString() });
+ } else {
+ logger.info(
+ "Remote Authentication Failed for User: \"{}\", from Server: {}, Reason:{}",
+ new Object[] { userName, aaaServer.getAddress(),
+ rcResponse.getStatus().toString() });
+ }
+ }
+ }
+
+ if (!remotelyAuthenticated) {
+ UserConfig localUser = this.localUserConfigList.get(userName);
+ if (localUser == null) {
+ logger.info(
+ "Local Authentication Failed for User:\"{}\", Reason: "
+ + "user not found in Local Database", userName);
+ return (AuthResultEnum.AUTH_INVALID_LOC_USER);
+ }
+ rcResponse = localUser.authenticate(password);
+ if (rcResponse.getStatus() != AuthResultEnum.AUTH_ACCEPT_LOC) {
+ logger.info(
+ "Local Authentication Failed for User: \"{}\", Reason: {}",
+ userName, rcResponse.getStatus().toString());
+
+ return (rcResponse.getStatus());
+ }
+ logger.info("Local Authentication Succeeded for User: \"{}\"",
+ userName);
+ }
+
+ /*
+ * Authentication succeeded
+ */
+ result = new AuthenticatedUser(userName);
+
+ /*
+ * Extract attributes from response All the information we are
+ * interested in is in the first Cisco VSA (vendor specific attribute).
+ * Just process the first VSA and return
+ */
+ String attributes = (rcResponse.getData() != null && !rcResponse
+ .getData().isEmpty()) ? rcResponse.getData().get(0) : null;
+
+ /*
+ * Check if the authorization information is present
+ */
+ authorizationInfoIsPresent = checkAuthorizationInfo(attributes);
+
+ /*
+ * The AAA server was only used to perform the authentication Look for
+ * locally stored authorization info for this user If found, add the
+ * data to the rcResponse
+ */
+ if (remotelyAuthenticated && !authorizationInfoIsPresent) {
+ logger.info(
+ "No Remote Authorization Info provided by Server for User: \"{}\"",
+ userName);
+ logger.info(
+ "Looking for Local Authorization Info for User: \"{}\"",
+ userName);
+
+ AuthorizationConfig resource = authorizationConfList.get(userName);
+ if (resource != null) {
+ logger.info("Found Local Authorization Info for User: \"{}\"",
+ userName);
+ attributes = resource.getRolesString();
+
+ }
+ authorizationInfoIsPresent = checkAuthorizationInfo(attributes);
+ }
+
+ /*
+ * Common response parsing for local & remote authenticated user Looking
+ * for authorized resources, detecting attributes' validity
+ */
+ if (authorizationInfoIsPresent) {
+ // Identifying the administrative role
+ result.setRoleList(attributes.split(" "));
+ authorized = true;
+ } else {
+ logger.info("Not able to find Authorization Info for User: \"{}\"",
+ userName);
+ }
+
+ /*
+ * Add profile for authenticated user
+ */
+ putUserInActiveList(userName, result);
+ if (authorized) {
+ logger.info("User \"{}\" authorized for the following role(s): {}",
+ userName, result.getUserRoles());
+ } else {
+ logger.info("User \"{}\" Not Authorized for any role ", userName);
+ }
+
+ return rcResponse.getStatus();
+ }
+
+ // Check in the attributes string whether or not authorization information
+ // is present
+ private boolean checkAuthorizationInfo(String attributes) {
+ return (attributes != null && !attributes.isEmpty());
+ }
+
+ private void putUserInActiveList(String user, AuthenticatedUser result) {
+ activeUsers.put(user, result);
+ }
+
+ private void removeUserFromActiveList(String user) {
+ if (!activeUsers.containsKey(user)) {
+ // as cookie persists in cache, we can get logout for unexisting
+ // active users
+ return;
+ }
+ activeUsers.remove(user);
+ }
+
+ @Override
+ public Status saveLocalUserList() {
+ // Publish the save config event to the cluster nodes
+ localUserListSaveConfigEvent.put(new Date().getTime(), SAVE);
+ return saveLocalUserListInternal();
+ }
+
+ private Status saveLocalUserListInternal() {
+ ObjectWriter objWriter = new ObjectWriter();
+ return objWriter.write(new ConcurrentHashMap<String, UserConfig>(
+ localUserConfigList), usersFileName);
+ }
+
+ @Override
+ public Status saveAAAServerList() {
+ // Publish the save config event to the cluster nodes
+ remoteServerSaveConfigEvent.put(new Date().getTime(), SAVE);
+ return saveAAAServerListInternal();
+ }
+
+ private Status saveAAAServerListInternal() {
+ ObjectWriter objWriter = new ObjectWriter();
+ return objWriter.write(new ConcurrentHashMap<String, ServerConfig>(
+ remoteServerConfigList), serversFileName);
+ }
+
+ @Override
+ public Status saveAuthorizationList() {
+ // Publish the save config event to the cluster nodes
+ authorizationSaveConfigEvent.put(new Date().getTime(), SAVE);
+ return saveAuthorizationListInternal();
+ }
+
+ private Status saveAuthorizationListInternal() {
+ ObjectWriter objWriter = new ObjectWriter();
+ return objWriter.write(
+ new ConcurrentHashMap<String, AuthorizationConfig>(
+ authorizationConfList), authFileName);
+ }
+
+ @Override
+ public Object readObject(ObjectInputStream ois)
+ throws FileNotFoundException, IOException, ClassNotFoundException {
+ // Perform the class deserialization locally, from inside the package
+ // where the class is defined
+ return ois.readObject();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadUserConfig() {
+ ObjectReader objReader = new ObjectReader();
+ ConcurrentMap<String, UserConfig> confList = (ConcurrentMap<String, UserConfig>) objReader
+ .read(this, usersFileName);
+
+ if (confList == null) {
+ return;
+ }
+
+ for (UserConfig conf : confList.values()) {
+ addLocalUser(conf);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadServerConfig() {
+ ObjectReader objReader = new ObjectReader();
+ ConcurrentMap<String, ServerConfig> confList = (ConcurrentMap<String, ServerConfig>) objReader
+ .read(this, serversFileName);
+
+ if (confList == null) {
+ return;
+ }
+
+ for (ServerConfig conf : confList.values()) {
+ addAAAServer(conf);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadAuthConfig() {
+ ObjectReader objReader = new ObjectReader();
+ ConcurrentMap<String, AuthorizationConfig> confList = (ConcurrentMap<String, AuthorizationConfig>) objReader
+ .read(this, authFileName);
+
+ if (confList == null) {
+ return;
+ }
+
+ for (AuthorizationConfig conf : confList.values()) {
+ addAuthInfo(conf);
+ }
+ }
+
+ /*
+ * Interaction with GUI START
+ */
+ public Status addRemoveLocalUser(UserConfig AAAconf, boolean delete) {
+ // UserConfig Validation check
+ Status validCheck = AAAconf.validate();
+ if (!validCheck.isSuccess()) {
+ return validCheck;
+ }
+
+ // Update Config database
+ if (delete) {
+ if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) {
+ String msg = "Invalid Request: Default Network Admin User "
+ + "cannot be deleted";
+ logger.debug(msg);
+ return new Status(StatusCode.NOTALLOWED, msg);
+ }
+ localUserConfigList.remove(AAAconf.getUser());
+ /*
+ * A user account has been removed form local database, we assume
+ * admin does not want this user to stay connected, in case he has
+ * an open session. So we clean the active list as well.
+ */
+ removeUserFromActiveList(AAAconf.getUser());
+ } else {
+ if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) {
+ String msg = "Invalid Request: Default Network Admin User "
+ + "cannot be added";
+ logger.debug(msg);
+ return new Status(StatusCode.NOTALLOWED, msg);
+ }
+ localUserConfigList.put(AAAconf.getUser(), AAAconf);
+ }
+
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ private Status addRemoveAAAServer(ServerConfig AAAconf, boolean delete) {
+ // Validation check
+ if (!AAAconf.isValid()) {
+ String msg = "Invalid Server configuration";
+ logger.warn(msg);
+ return new Status(StatusCode.BADREQUEST, msg);
+ }
+
+ // Update configuration database
+ if (delete) {
+ remoteServerConfigList.remove(AAAconf.getAddress());
+ } else {
+ remoteServerConfigList.put(AAAconf.getAddress(), AAAconf);
+ }
+
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ private Status addRemoveAuthInfo(AuthorizationConfig AAAconf, boolean delete) {
+ Status configCheck = AAAconf.validate();
+ if (!configCheck.isSuccess()) {
+ String msg = "Invalid Authorization configuration: "
+ + configCheck.getDescription();
+ logger.warn(msg);
+ return new Status(StatusCode.BADREQUEST, msg);
+ }
+
+ // Update configuration database
+ if (delete) {
+ authorizationConfList.remove(AAAconf.getUser());
+ } else {
+ authorizationConfList.put(AAAconf.getUser(), AAAconf);
+ }
+
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ @Override
+ public Status addLocalUser(UserConfig AAAconf) {
+ return addRemoveLocalUser(AAAconf, false);
+ }
+
+ @Override
+ public Status removeLocalUser(UserConfig AAAconf) {
+ return addRemoveLocalUser(AAAconf, true);
+ }
+
+ @Override
+ public Status removeLocalUser(String userName) {
+ if (userName == null || userName.trim().isEmpty()) {
+ return new Status(StatusCode.BADREQUEST, "Invalid user name");
+ }
+ if (!localUserConfigList.containsKey(userName)) {
+ return new Status(StatusCode.NOTFOUND, "User does not exist");
+ }
+ return addRemoveLocalUser(localUserConfigList.get(userName), true);
+ }
+
+ @Override
+ public Status addAAAServer(ServerConfig AAAconf) {
+ return addRemoveAAAServer(AAAconf, false);
+ }
+
+ @Override
+ public Status removeAAAServer(ServerConfig AAAconf) {
+ return addRemoveAAAServer(AAAconf, true);
+ }
+
+ @Override
+ public Status addAuthInfo(AuthorizationConfig AAAconf) {
+ return addRemoveAuthInfo(AAAconf, false);
+ }
+
+ @Override
+ public Status removeAuthInfo(AuthorizationConfig AAAconf) {
+ return addRemoveAuthInfo(AAAconf, true);
+ }
+
+ @Override
+ public List<UserConfig> getLocalUserList() {
+ return new ArrayList<UserConfig>(localUserConfigList.values());
+ }
+
+ @Override
+ public List<ServerConfig> getAAAServerList() {
+ return new ArrayList<ServerConfig>(remoteServerConfigList.values());
+ }
+
+ @Override
+ public List<AuthorizationConfig> getAuthorizationList() {
+ return new ArrayList<AuthorizationConfig>(
+ authorizationConfList.values());
+ }
+
+ @Override
+ public Status changeLocalUserPassword(String user, String curPassword,
+ String newPassword) {
+ UserConfig targetConfigEntry = null;
+
+ // update configuration entry
+ targetConfigEntry = localUserConfigList.get(user);
+ if (targetConfigEntry == null) {
+ return new Status(StatusCode.NOTFOUND, "User not found");
+ }
+ Status status = targetConfigEntry
+ .update(curPassword, newPassword, null);
+ if (!status.isSuccess()) {
+ return status;
+ }
+ // Trigger cluster update
+ localUserConfigList.put(user, targetConfigEntry);
+
+ logger.info("Password changed for User \"{}\"", user);
+
+ return status;
+ }
+
+ @Override
+ public void userLogout(String userName) {
+ // TODO: if user was authenticated through AAA server, send
+ // Acct-Status-Type=stop message to server with logout as reason
+ removeUserFromActiveList(userName);
+ logger.info("User \"{}\" logged out", userName);
+ }
+
+ /*
+ * This function will get called by http session mgr when session times out
+ */
+ @Override
+ public void userTimedOut(String userName) {
+ // TODO: if user was authenticated through AAA server, send
+ // Acct-Status-Type=stop message to server with timeout as reason
+ removeUserFromActiveList(userName);
+ logger.info("User \"{}\" timed out", userName);
+ }
+
+ @Override
+ public String getAccessDate(String user) {
+ return this.activeUsers.get(user).getAccessDate();
+ }
+
+ @Override
+ public synchronized Map<String, List<String>> getUserLoggedIn() {
+ Map<String, List<String>> loggedInList = new HashMap<String, List<String>>();
+ for (Map.Entry<String, AuthenticatedUser> user : activeUsers.entrySet()) {
+ String userNameShow = user.getKey();
+ loggedInList.put(userNameShow, user.getValue().getUserRoles());
+ }
+ return loggedInList;
+ }
+
+ /*
+ * Interaction with GUI END
+ */
+
+ /*
+ * Cluster notifications
+ */
+
+ @Override
+ public void entryCreated(Long key, String cacheName, boolean originLocal) {
+ // don't react on this event
+ }
+
+ @Override
+ public void entryUpdated(Long key, String new_value, String cacheName,
+ boolean originLocal) {
+ if (cacheName.equals("localUserSaveConfigEvent")) {
+ this.saveLocalUserListInternal();
+ } else if (cacheName.equals("remoteServerSaveConfigEvent")) {
+ this.saveAAAServerListInternal();
+ } else if (cacheName.equals("authorizationSaveConfigEvent")) {
+ this.saveAuthorizationListInternal();
+ }
+ }
+
+ @Override
+ public void entryDeleted(Long key, String cacheName, boolean originLocal) {
+ // don't react on this event
+ }
+
+ public void _umAddUser(CommandInterpreter ci) {
+ String userName = ci.nextArgument();
+ String password = ci.nextArgument();
+ String role = ci.nextArgument();
+
+ List<String> roles = new ArrayList<String>();
+ while (role != null) {
+ if (!role.trim().isEmpty()) {
+ roles.add(role);
+ }
+ role = ci.nextArgument();
+ }
+
+ if (userName == null || userName.trim().isEmpty() || password == null
+ || password.trim().isEmpty() || roles == null
+ || roles.isEmpty()) {
+ ci.println("Invalid Arguments");
+ ci.println("umAddUser <user_name> <password> <user_role>");
+ return;
+ }
+ ci.print(this.addLocalUser(new UserConfig(userName, password, roles)));
+ }
+
+ public void _umRemUser(CommandInterpreter ci) {
+ String userName = ci.nextArgument();
+
+ if (userName == null || userName.trim().isEmpty()) {
+ ci.println("Invalid Arguments");
+ ci.println("umRemUser <user_name>");
+ return;
+ }
+ UserConfig target = localUserConfigList.get(userName);
+ if (target == null) {
+ ci.println("User not found");
+ return;
+ }
+ ci.println(this.removeLocalUser(target));
+ }
+
+ public void _umGetUsers(CommandInterpreter ci) {
+ for (UserConfig conf : this.getLocalUserList()) {
+ ci.println(conf.getUser() + " " + conf.getRoles());
+ }
+ }
+
+ public void _addAAAServer(CommandInterpreter ci) {
+ String server = ci.nextArgument();
+ String secret = ci.nextArgument();
+ String protocol = ci.nextArgument();
+
+ if (server == null || secret == null || protocol == null) {
+ ci.println("Usage : addAAAServer <server> <secret> <protocol>");
+ return;
+ }
+ ServerConfig s = new ServerConfig(server, secret, protocol);
+ addAAAServer(s);
+ }
+
+ public void _removeAAAServer(CommandInterpreter ci) {
+ String server = ci.nextArgument();
+ String secret = ci.nextArgument();
+ String protocol = ci.nextArgument();
+
+ if (server == null || secret == null || protocol == null) {
+ ci.println("Usage : addAAAServer <server> <secret> <protocol>");
+ return;
+ }
+ ServerConfig s = new ServerConfig(server, secret, protocol);
+ removeAAAServer(s);
+ }
+
+ public void _printAAAServers(CommandInterpreter ci) {
+ for (ServerConfig aaaServer : remoteServerConfigList.values()) {
+ ci.println(aaaServer.getAddress() + "-" + aaaServer.getProtocol());
+ }
+ }
+
+ @Override
+ public String getHelp() {
+ StringBuffer help = new StringBuffer();
+ return help.toString();
+ }
+
+ void setClusterGlobalService(IClusterGlobalServices s) {
+ logger.debug("Cluster Service Global set");
+ this.clusterGlobalService = s;
+ }
+
+ void unsetClusterGlobalService(IClusterGlobalServices s) {
+ if (this.clusterGlobalService == s) {
+ logger.debug("Cluster Service Global removed!");
+ this.clusterGlobalService = null;
+ }
+ }
+
+ void unsetContainerAuthClient(IContainerAuthorization s) {
+ if (this.containerAuthorizationClient == s) {
+ this.containerAuthorizationClient = null;
+ }
+ }
+
+ void setContainerAuthClient(IContainerAuthorization s) {
+ this.containerAuthorizationClient = s;
+ }
+
+ void setAppAuthClient(IResourceAuthorization s) {
+ this.applicationAuthorizationClients.add(s);
+ }
+
+ void unsetAppAuthClient(IResourceAuthorization s) {
+ this.applicationAuthorizationClients.remove(s);
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ *
+ */
+ void init() {
+ }
+
+ /**
+ * Function called by the dependency manager when at least one dependency
+ * become unsatisfied or when the component is shutting down because for
+ * example bundle is being stopped.
+ *
+ */
+ void destroy() {
+ }
+
+ /**
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
+ *
+ */
+ void start() {
+ authProviders = new ConcurrentHashMap<String, IAAAProvider>();
+ // Instantiate cluster synced variables
+ allocateCaches();
+ retrieveCaches();
+
+ // Read startup configuration and populate databases
+ loadConfigurations();
+
+ // Make sure default Network Admin account is there
+ checkDefaultNetworkAdmin();
+ BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+ .getBundleContext();
+ bundleContext.registerService(CommandProvider.class.getName(), this,
+ null);
+ }
+
+ /**
+ * Function called by the dependency manager before the services exported by
+ * the component are unregistered, this will be followed by a "destroy ()"
+ * calls
+ *
+ */
+ void stop() {
+ }
+
+ @Override
+ public List<String> getUserRoles(String userName) {
+ List<String> roles = null;
+ if (userName != null) {
+ /*
+ * First look in active users then in local configured users,
+ * finally in local authorized users
+ */
+ if (activeUsers.containsKey(userName)) {
+ roles = activeUsers.get(userName).getUserRoles();
+ } else if (localUserConfigList.containsKey(userName)) {
+ roles = localUserConfigList.get(userName).getRoles();
+ } else if (authorizationConfList.containsKey(userName)) {
+ roles = authorizationConfList.get(userName).getRoles();
+ }
+ }
+ return (roles == null) ? new ArrayList<String>(0) : roles;
+ }
+
+ @Override
+ public UserLevel getUserLevel(String username) {
+ // Returns the highest controller user level for the passed user
+ List<String> rolesNames = getUserRoles(username);
+
+ if (rolesNames.isEmpty()) {
+ return UserLevel.NOUSER;
+ }
+
+ // Check against the well known controller roles first
+ if (rolesNames.contains(UserLevel.SYSTEMADMIN.toString())) {
+ return UserLevel.SYSTEMADMIN;
+ }
+ if (rolesNames.contains(UserLevel.NETWORKADMIN.toString())) {
+ return UserLevel.NETWORKADMIN;
+ }
+ if (rolesNames.contains(UserLevel.NETWORKOPERATOR.toString())) {
+ return UserLevel.NETWORKOPERATOR;
+ }
+ // Check if container user now
+ if (containerAuthorizationClient != null) {
+ for (String roleName : rolesNames) {
+ if (containerAuthorizationClient.isApplicationRole(roleName)) {
+ return UserLevel.CONTAINERUSER;
+ }
+ }
+ }
+ // Finally check if application user
+ if (applicationAuthorizationClients != null) {
+ for (String roleName : rolesNames) {
+ for (IResourceAuthorization client : this.applicationAuthorizationClients) {
+ if (client.isApplicationRole(roleName)) {
+ return UserLevel.APPUSER;
+ }
+ }
+ }
+ }
+ return UserLevel.NOUSER;
+ }
+
+
+ @Override
+ public List<UserLevel> getUserLevels(String username) {
+ // Returns the controller user levels for the passed user
+ List<String> rolesNames = getUserRoles(username);
+ List<UserLevel> levels = new ArrayList<UserLevel>();
+
+ if (rolesNames.isEmpty()) {
+ return levels;
+ }
+
+ // Check against the well known controller roles first
+ if (rolesNames.contains(UserLevel.SYSTEMADMIN.toString())) {
+ levels.add(UserLevel.SYSTEMADMIN);
+ }
+ if (rolesNames.contains(UserLevel.NETWORKADMIN.toString())) {
+ levels.add(UserLevel.NETWORKADMIN);
+ }
+ if (rolesNames.contains(UserLevel.NETWORKOPERATOR.toString())) {
+ levels.add(UserLevel.NETWORKOPERATOR);
+ }
+ // Check if container user now
+ if (containerAuthorizationClient != null) {
+ for (String roleName : rolesNames) {
+ if (containerAuthorizationClient.isApplicationRole(roleName)) {
+ levels.add(UserLevel.CONTAINERUSER);
+ break;
+ }
+ }
+ }
+ // Finally check if application user
+ if (applicationAuthorizationClients != null) {
+ for (String roleName : rolesNames) {
+ for (IResourceAuthorization client : this.applicationAuthorizationClients) {
+ if (client.isApplicationRole(roleName)) {
+ levels.add(UserLevel.APPUSER);
+ break;
+ }
+ }
+ }
+ }
+ return levels;
+ }
+
+ @Override
+ public Status saveConfiguration() {
+ boolean success = true;
+ Status ret = saveLocalUserList();
+ if (!ret.isSuccess()) {
+ success = false;
+ }
+ ret = saveAAAServerList();
+ if (!ret.isSuccess()) {
+ success = false;
+ }
+ ret = saveAuthorizationList();
+ if (!ret.isSuccess()) {
+ success = false;
+ }
+
+ if (success) {
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ return new Status(StatusCode.INTERNALERROR,
+ "Failed to save user configurations");
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String username)
+ throws UsernameNotFoundException {
+ AuthenticatedUser user = activeUsers.get(username);
+
+ if (user != null) {
+ boolean enabled = true;
+ boolean accountNonExpired = true;
+ boolean credentialsNonExpired = true;
+ boolean accountNonLocked = true;
+
+ return new User(username, localUserConfigList.get(username)
+ .getPassword(), enabled, accountNonExpired,
+ credentialsNonExpired, accountNonLocked,
+ user.getGrantedAuthorities(getUserLevel(username)));
+ } else {
+ throw new UsernameNotFoundException("User not found " + username);
+ }
+ }
+
+ @Override
+ public boolean supports(Class<?> authentication) {
+ return UsernamePasswordAuthenticationToken.class
+ .isAssignableFrom(authentication);
+
+ }
+
+ @Override
+ public SecurityContextRepository getSecurityContextRepo() {
+ return securityContextRepo;
+ }
+
+ public void setSecurityContextRepo(
+ SecurityContextRepository securityContextRepo) {
+ this.securityContextRepo = securityContextRepo;
+ }
+
+ @Override
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+
+ if (StringUtils.isBlank((String) authentication.getCredentials())
+ || StringUtils.isBlank((String) authentication.getPrincipal())) {
+ throw new BadCredentialsException(
+ "Username or credentials did not match");
+ }
+
+ AuthResultEnum result = authenticate(
+ (String) authentication.getPrincipal(),
+ (String) authentication.getCredentials());
+ if (result.equals(AuthResultEnum.AUTHOR_PASS)
+ || result.equals(AuthResultEnum.AUTH_ACCEPT_LOC)
+ || result.equals(AuthResultEnum.AUTH_ACCEPT)) {
+
+ AuthenticatedUser user = activeUsers.get(authentication
+ .getPrincipal().toString());
+
+ if (user == null) {
+ throw new AuthenticationServiceException(
+ "Authentication Failure");
+ }
+
+ authentication = new UsernamePasswordAuthenticationToken(
+ authentication.getPrincipal(),
+ authentication.getCredentials(),
+ user.getGrantedAuthorities(getUserLevel(authentication
+ .getName())));
+ return authentication;
+
+ } else {
+ throw new BadCredentialsException(
+ "Username or credentials did not match");
+ }
+
+ }
+
+ // Following are setters for use in unit testing
+ void setLocalUserConfigList(ConcurrentMap<String, UserConfig> ucl) {
+ if (ucl != null) {
+ this.localUserConfigList = ucl;
+ }
+ }
+
+ void setRemoteServerConfigList(ConcurrentMap<String, ServerConfig> scl) {
+ if (scl != null) {
+ this.remoteServerConfigList = scl;
+ }
+ }
+
+ void setAuthorizationConfList(ConcurrentMap<String, AuthorizationConfig> acl) {
+ if (acl != null) {
+ this.authorizationConfList = acl;
+ }
+ }
+
+ void setActiveUsers(ConcurrentMap<String, AuthenticatedUser> au) {
+ if (au != null) {
+ this.activeUsers = au;
+ }
+ }
+
+ void setAuthProviders(ConcurrentMap<String, IAAAProvider> ap) {
+ if (ap != null) {
+ this.authProviders = ap;
+ }
+ }
+
+ @Override
+ public ISessionManager getSessionManager() {
+ return this.sessionMgr;
+ }
+
+ public void setSessionMgr(ISessionManager sessionMgr) {
+ this.sessionMgr = sessionMgr;
+ }
+
+ @Override
+ public String getPassword(String username) {
+ return localUserConfigList.get(username).getPassword();
+ }
+
+ @Override
+ public boolean isRoleInUse(String role) {
+ if (role == null || role.isEmpty()) {
+ return false;
+ }
+ // Check against controller roles
+ if (role.equals(UserLevel.SYSTEMADMIN.toString())
+ || role.equals(UserLevel.NETWORKADMIN.toString())
+ || role.equals(UserLevel.NETWORKOPERATOR.toString())) {
+ return true;
+ }
+ // Check if container roles
+ if (containerAuthorizationClient != null) {
+ if (containerAuthorizationClient.isApplicationRole(role)) {
+ return true;
+ }
+ }
+ // Finally if application role
+ if (applicationAuthorizationClients != null) {
+ for (IResourceAuthorization client : this.applicationAuthorizationClients) {
+ if (client.isApplicationRole(role)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}