org.opendaylight.controller.usermanager.internal.UserManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.controller.usermanager.internal.UserManagerImpl.java

Source

/*
 * 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.AuthenticatedUser;
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.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;
    }
}