Merge "UI support for multiple host per port"
[controller.git] / opendaylight / usermanager / implementation / src / main / java / org / opendaylight / controller / usermanager / internal / UserManager.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.usermanager.internal;
10
11 import java.io.File;
12 import java.io.FileInputStream;
13 import java.io.FileNotFoundException;
14 import java.io.IOException;
15 import java.io.ObjectInputStream;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.EnumSet;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26
27 import org.apache.commons.lang3.StringUtils;
28 import org.eclipse.osgi.framework.console.CommandInterpreter;
29 import org.eclipse.osgi.framework.console.CommandProvider;
30 import org.opendaylight.controller.clustering.services.CacheConfigException;
31 import org.opendaylight.controller.clustering.services.CacheExistException;
32 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
33 import org.opendaylight.controller.clustering.services.IClusterServices;
34 import org.opendaylight.controller.configuration.IConfigurationAware;
35 import org.opendaylight.controller.containermanager.IContainerAuthorization;
36 import org.opendaylight.controller.sal.authorization.AuthResultEnum;
37 import org.opendaylight.controller.sal.authorization.IResourceAuthorization;
38 import org.opendaylight.controller.sal.authorization.UserLevel;
39 import org.opendaylight.controller.sal.utils.StatusCode;
40 import org.opendaylight.controller.sal.utils.GlobalConstants;
41 import org.opendaylight.controller.sal.utils.IObjectReader;
42 import org.opendaylight.controller.sal.utils.ObjectReader;
43 import org.opendaylight.controller.sal.utils.ObjectWriter;
44 import org.opendaylight.controller.sal.utils.Status;
45 import org.opendaylight.controller.usermanager.AuthResponse;
46 import org.opendaylight.controller.usermanager.AuthenticatedUser;
47 import org.opendaylight.controller.usermanager.AuthorizationConfig;
48 import org.opendaylight.controller.usermanager.IAAAProvider;
49 import org.opendaylight.controller.usermanager.ISessionManager;
50 import org.opendaylight.controller.usermanager.IUserManager;
51 import org.opendaylight.controller.usermanager.ServerConfig;
52 import org.opendaylight.controller.usermanager.UserConfig;
53 import org.opendaylight.controller.usermanager.security.SessionManager;
54 import org.opendaylight.controller.usermanager.security.UserSecurityContextRepository;
55
56 import org.osgi.framework.BundleContext;
57 import org.osgi.framework.FrameworkUtil;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.springframework.security.authentication.AuthenticationProvider;
61 import org.springframework.security.authentication.AuthenticationServiceException;
62 import org.springframework.security.authentication.BadCredentialsException;
63 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
64 import org.springframework.security.core.Authentication;
65 import org.springframework.security.core.AuthenticationException;
66 import org.springframework.security.core.userdetails.User;
67 import org.springframework.security.core.userdetails.UserDetails;
68 import org.springframework.security.core.userdetails.UsernameNotFoundException;
69 import org.springframework.security.web.context.SecurityContextRepository;
70
71 /**
72  * The internal implementation of the User Manager.
73  */
74 public class UserManager implements IUserManager, IObjectReader,
75         IConfigurationAware, CommandProvider, AuthenticationProvider {
76     private static final Logger logger = LoggerFactory.getLogger(UserManager.class);
77     private static final String DEFAULT_ADMIN = "admin";
78     private static final String DEFAULT_ADMIN_PASSWORD = "admin";
79     private static final String DEFAULT_ADMIN_ROLE = UserLevel.NETWORKADMIN.toString();
80     private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
81     private static final String USERS_FILE_NAME = ROOT + "users.conf";
82     private static final String SERVERS_FILE_NAME = ROOT + "servers.conf";
83     private static final String AUTH_FILE_NAME = ROOT + "authorization.conf";
84     private static final String RECOVERY_FILE = ROOT + "NETWORK_ADMIN_PASSWORD_RECOVERY";
85     private ConcurrentMap<String, UserConfig> localUserConfigList;
86     private ConcurrentMap<String, ServerConfig> remoteServerConfigList;
87     // local authorization info for remotely authenticated users
88     private ConcurrentMap<String, AuthorizationConfig> authorizationConfList;
89     private ConcurrentMap<String, AuthenticatedUser> activeUsers;
90     private ConcurrentMap<String, IAAAProvider> authProviders;
91     private IClusterGlobalServices clusterGlobalService = null;
92     private SecurityContextRepository securityContextRepo = new UserSecurityContextRepository();
93     private IContainerAuthorization containerAuthorizationClient;
94     private Set<IResourceAuthorization> applicationAuthorizationClients;
95     private ISessionManager sessionMgr = new SessionManager();
96
97     public boolean addAAAProvider(IAAAProvider provider) {
98         if (provider == null || provider.getName() == null
99                 || provider.getName().trim().isEmpty()) {
100             return false;
101         }
102         if (authProviders.get(provider.getName()) != null) {
103             return false;
104         }
105
106         authProviders.put(provider.getName(), provider);
107         return true;
108     }
109
110     public void removeAAAProvider(IAAAProvider provider) {
111         authProviders.remove(provider.getName());
112     }
113
114     public IAAAProvider getAAAProvider(String name) {
115         return authProviders.get(name);
116     }
117
118     @Override
119     public Set<String> getAAAProviderNames() {
120         return authProviders.keySet();
121     }
122
123     private void allocateCaches() {
124         this.applicationAuthorizationClients = Collections.synchronizedSet(new HashSet<IResourceAuthorization>());
125         if (clusterGlobalService == null) {
126             logger.error("un-initialized clusterGlobalService, can't create cache");
127             return;
128         }
129
130         try {
131             clusterGlobalService.createCache("usermanager.localUserConfigList",
132                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
133
134             clusterGlobalService.createCache(
135                     "usermanager.remoteServerConfigList",
136                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
137
138             clusterGlobalService.createCache(
139                     "usermanager.authorizationConfList",
140                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
141
142             clusterGlobalService.createCache("usermanager.activeUsers",
143                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
144         } catch (CacheConfigException cce) {
145             logger.error("Cache configuration invalid - check cache mode");
146         } catch (CacheExistException ce) {
147             logger.debug("Skipping cache creation as already present");
148         }
149     }
150
151     @SuppressWarnings({ "unchecked" })
152     private void retrieveCaches() {
153         if (clusterGlobalService == null) {
154             logger.error("un-initialized clusterService, can't retrieve cache");
155             return;
156         }
157
158         activeUsers = (ConcurrentMap<String, AuthenticatedUser>) clusterGlobalService
159                 .getCache("usermanager.activeUsers");
160         if (activeUsers == null) {
161             logger.error("Failed to get cache for activeUsers");
162         }
163
164         localUserConfigList = (ConcurrentMap<String, UserConfig>) clusterGlobalService
165                 .getCache("usermanager.localUserConfigList");
166         if (localUserConfigList == null) {
167             logger.error("Failed to get cache for localUserConfigList");
168         }
169
170         remoteServerConfigList = (ConcurrentMap<String, ServerConfig>) clusterGlobalService
171                 .getCache("usermanager.remoteServerConfigList");
172         if (remoteServerConfigList == null) {
173             logger.error("Failed to get cache for remoteServerConfigList");
174         }
175
176         authorizationConfList = (ConcurrentMap<String, AuthorizationConfig>) clusterGlobalService
177                 .getCache("usermanager.authorizationConfList");
178         if (authorizationConfList == null) {
179             logger.error("Failed to get cache for authorizationConfList");
180         }
181     }
182
183     private void loadConfigurations() {
184         // To encode and decode user and server configuration objects
185         loadSecurityKeys();
186
187         /*
188          * Do not load local startup file if we already got the configurations
189          * synced from another cluster node
190          */
191         if (localUserConfigList.isEmpty()) {
192             loadUserConfig();
193         }
194         if (remoteServerConfigList.isEmpty()) {
195             loadServerConfig();
196         }
197         if (authorizationConfList.isEmpty()) {
198             loadAuthConfig();
199         }
200     }
201
202     private void loadSecurityKeys() {
203
204     }
205
206     private void checkDefaultNetworkAdmin() {
207         // If startup config is not there, it's old or it was deleted,
208         // need to add Default Network Admin User
209         if (!localUserConfigList.containsKey(DEFAULT_ADMIN)) {
210             List<String> roles = new ArrayList<String>(1);
211             roles.add(DEFAULT_ADMIN_ROLE);
212             localUserConfigList.put(DEFAULT_ADMIN, new UserConfig(DEFAULT_ADMIN, DEFAULT_ADMIN_PASSWORD, roles));
213         }
214     }
215
216     private void checkPasswordRecovery() {
217         final String fileDescription = "Default Network Administrator password recovery file";
218         try {
219             FileInputStream fis = new FileInputStream(UserManager.RECOVERY_FILE);
220             /*
221              * Recovery file detected, remove current default network
222              * administrator entry from local users configuration list.
223              * Warn user and delete recovery file.
224              */
225             this.localUserConfigList.remove(UserManager.DEFAULT_ADMIN);
226             logger.info("Default Network Administrator password has been reset to factory default.");
227             logger.info("Please change the default Network Administrator password as soon as possible");
228             File filePointer = new File(UserManager.RECOVERY_FILE);
229             boolean status = filePointer.delete();
230             if (!status) {
231                 logger.warn("Failed to delete {}", fileDescription);
232             } else {
233                 logger.trace("{} deleted", fileDescription);
234             }
235             fis.close();
236         } catch (FileNotFoundException fnf) {
237             logger.trace("{} not present", fileDescription);
238         } catch (IOException e) {
239             logger.warn("Failed to close file stream for {}", fileDescription);
240         }
241     }
242
243     @Override
244     public AuthResultEnum authenticate(String userName, String password) {
245         IAAAProvider aaaClient;
246         AuthResponse rcResponse = null;
247         AuthenticatedUser result;
248         boolean remotelyAuthenticated = false;
249         boolean authorizationInfoIsPresent = false;
250         boolean authorized = false;
251
252         /*
253          * Attempt remote authentication first if server is configured
254          */
255         for (ServerConfig aaaServer : remoteServerConfigList.values()) {
256             String protocol = aaaServer.getProtocol();
257             aaaClient = this.getAAAProvider(protocol);
258             if (aaaClient != null) {
259                 rcResponse = aaaClient.authService(userName, password,
260                         aaaServer.getAddress(), aaaServer.getSecret());
261                 if (rcResponse.getStatus() == AuthResultEnum.AUTH_ACCEPT) {
262                     logger.info(
263                             "Remote Authentication Succeeded for User: \"{}\", by Server: {}",
264                             userName, aaaServer.getAddress());
265                     remotelyAuthenticated = true;
266                     break;
267                 } else if (rcResponse.getStatus() == AuthResultEnum.AUTH_REJECT) {
268                     logger.info(
269                             "Remote Authentication Rejected User: \"{}\", from Server: {}, Reason:{}",
270                             new Object[] { userName, aaaServer.getAddress(),
271                                     rcResponse.getStatus().toString() });
272                 } else {
273                     logger.info(
274                             "Remote Authentication Failed for User: \"{}\", from Server: {}, Reason:{}",
275                             new Object[] { userName, aaaServer.getAddress(),
276                                     rcResponse.getStatus().toString() });
277                 }
278             }
279         }
280
281         if (!remotelyAuthenticated) {
282             UserConfig localUser = this.localUserConfigList.get(userName);
283             if (localUser == null) {
284                 logger.info(
285                         "Local Authentication Failed for User:\"{}\", Reason: "
286                                 + "user not found in Local Database", userName);
287                 return (AuthResultEnum.AUTH_INVALID_LOC_USER);
288             }
289             rcResponse = localUser.authenticate(password);
290             if (rcResponse.getStatus() != AuthResultEnum.AUTH_ACCEPT_LOC) {
291                 logger.info(
292                         "Local Authentication Failed for User: \"{}\", Reason: {}",
293                         userName, rcResponse.getStatus().toString());
294
295                 return (rcResponse.getStatus());
296             }
297             logger.info("Local Authentication Succeeded for User: \"{}\"",
298                     userName);
299         }
300
301         /*
302          * Authentication succeeded
303          */
304         result = new AuthenticatedUser(userName);
305
306         /*
307          * Extract attributes from response All the information we are
308          * interested in is in the first Cisco VSA (vendor specific attribute).
309          * Just process the first VSA and return
310          */
311         String attributes = (rcResponse.getData() != null && !rcResponse
312                 .getData().isEmpty()) ? rcResponse.getData().get(0) : null;
313
314         /*
315          * Check if the authorization information is present
316          */
317         authorizationInfoIsPresent = checkAuthorizationInfo(attributes);
318
319         /*
320          * The AAA server was only used to perform the authentication Look for
321          * locally stored authorization info for this user If found, add the
322          * data to the rcResponse
323          */
324         if (remotelyAuthenticated && !authorizationInfoIsPresent) {
325             logger.info(
326                     "No Remote Authorization Info provided by Server for User: \"{}\"",
327                     userName);
328             logger.info(
329                     "Looking for Local Authorization Info for User: \"{}\"",
330                     userName);
331
332             AuthorizationConfig resource = authorizationConfList.get(userName);
333             if (resource != null) {
334                 logger.info("Found Local Authorization Info for User: \"{}\"",
335                         userName);
336                 attributes = resource.getRolesString();
337
338             }
339             authorizationInfoIsPresent = checkAuthorizationInfo(attributes);
340         }
341
342         /*
343          * Common response parsing for local & remote authenticated user Looking
344          * for authorized resources, detecting attributes' validity
345          */
346         if (authorizationInfoIsPresent) {
347             // Identifying the administrative role
348             result.setRoleList(attributes.split(" "));
349             authorized = true;
350         } else {
351             logger.info("Not able to find Authorization Info for User: \"{}\"",
352                     userName);
353         }
354
355         /*
356          * Add profile for authenticated user
357          */
358         putUserInActiveList(userName, result);
359         if (authorized) {
360             logger.info("User \"{}\" authorized for the following role(s): {}",
361                     userName, result.getUserRoles());
362         } else {
363             logger.info("User \"{}\" Not Authorized for any role ", userName);
364         }
365
366         return rcResponse.getStatus();
367     }
368
369     // Check in the attributes string whether or not authorization information
370     // is present
371     private boolean checkAuthorizationInfo(String attributes) {
372         return (attributes != null && !attributes.isEmpty());
373     }
374
375     private void putUserInActiveList(String user, AuthenticatedUser result) {
376         activeUsers.put(user, result);
377     }
378
379     private void removeUserFromActiveList(String user) {
380         if (!activeUsers.containsKey(user)) {
381             // as cookie persists in cache, we can get logout for unexisting
382             // active users
383             return;
384         }
385         activeUsers.remove(user);
386     }
387
388     @Override
389     public Status saveLocalUserList() {
390         return saveLocalUserListInternal();
391     }
392
393     private Status saveLocalUserListInternal() {
394         ObjectWriter objWriter = new ObjectWriter();
395         return objWriter.write(new ConcurrentHashMap<String, UserConfig>(
396                 localUserConfigList), USERS_FILE_NAME);
397     }
398
399     @Override
400     public Status saveAAAServerList() {
401         return saveAAAServerListInternal();
402     }
403
404     private Status saveAAAServerListInternal() {
405         ObjectWriter objWriter = new ObjectWriter();
406         return objWriter.write(new ConcurrentHashMap<String, ServerConfig>(
407                 remoteServerConfigList), SERVERS_FILE_NAME);
408     }
409
410     @Override
411     public Status saveAuthorizationList() {
412         return saveAuthorizationListInternal();
413     }
414
415     private Status saveAuthorizationListInternal() {
416         ObjectWriter objWriter = new ObjectWriter();
417         return objWriter.write(
418                 new ConcurrentHashMap<String, AuthorizationConfig>(
419                         authorizationConfList), AUTH_FILE_NAME);
420     }
421
422     @Override
423     public Object readObject(ObjectInputStream ois)
424             throws FileNotFoundException, IOException, ClassNotFoundException {
425         // Perform the class deserialization locally, from inside the package
426         // where the class is defined
427         return ois.readObject();
428     }
429
430     @SuppressWarnings("unchecked")
431     private void loadUserConfig() {
432         ObjectReader objReader = new ObjectReader();
433         ConcurrentMap<String, UserConfig> confList = (ConcurrentMap<String, UserConfig>) objReader
434                 .read(this, USERS_FILE_NAME);
435
436         if (confList == null) {
437             return;
438         }
439
440         for (UserConfig conf : confList.values()) {
441             addRemoveLocalUserInternal(conf, false);
442         }
443     }
444
445     @SuppressWarnings("unchecked")
446     private void loadServerConfig() {
447         ObjectReader objReader = new ObjectReader();
448         ConcurrentMap<String, ServerConfig> confList = (ConcurrentMap<String, ServerConfig>) objReader
449                 .read(this, SERVERS_FILE_NAME);
450
451         if (confList == null) {
452             return;
453         }
454
455         for (ServerConfig conf : confList.values()) {
456             addAAAServer(conf);
457         }
458     }
459
460     @SuppressWarnings("unchecked")
461     private void loadAuthConfig() {
462         ObjectReader objReader = new ObjectReader();
463         ConcurrentMap<String, AuthorizationConfig> confList = (ConcurrentMap<String, AuthorizationConfig>) objReader
464                 .read(this, AUTH_FILE_NAME);
465
466         if (confList == null) {
467             return;
468         }
469
470         for (AuthorizationConfig conf : confList.values()) {
471             addAuthInfo(conf);
472         }
473     }
474
475     /*
476      * Interaction with GUI START
477      */
478     private Status addRemoveLocalUser(UserConfig AAAconf, boolean delete) {
479         // UserConfig Validation check
480         Status validCheck = AAAconf.validate();
481         if (!validCheck.isSuccess()) {
482             return validCheck;
483         }
484
485         String user = AAAconf.getUser();
486
487         // Check default admin user
488         if (user.equals(UserManager.DEFAULT_ADMIN)) {
489             String msg = "Invalid Request: Default Network Admin  User cannot be " + ((delete)? "removed" : "added");
490             logger.debug(msg);
491             return new Status(StatusCode.NOTALLOWED, msg);
492         }
493
494         // Check user presence/conflict
495         StatusCode statusCode = null;
496         String reason = null;
497         if (delete && !localUserConfigList.containsKey(user)) {
498             reason = "not found";
499             statusCode = StatusCode.NOTFOUND;
500         } else if (!delete && localUserConfigList.containsKey(user)) {
501             reason = "already present";
502             statusCode = StatusCode.CONFLICT;
503         }
504         if (statusCode != null) {
505             String msg = String.format("User %s %s in configuration database", user, reason);
506             logger.debug(msg);
507             return new Status(statusCode, msg);
508         }
509
510         return addRemoveLocalUserInternal(AAAconf, delete);
511     }
512
513     private Status addRemoveLocalUserInternal(UserConfig AAAconf, boolean delete) {
514         // Update Config database
515         if (delete) {
516             localUserConfigList.remove(AAAconf.getUser());
517             /*
518              * A user account has been removed form local database, we assume
519              * admin does not want this user to stay connected, in case he has
520              * an open session. So we clean the active list as well.
521              */
522             removeUserFromActiveList(AAAconf.getUser());
523         } else {
524             localUserConfigList.put(AAAconf.getUser(), AAAconf);
525         }
526
527         return new Status(StatusCode.SUCCESS);
528     }
529
530     private Status addRemoveAAAServer(ServerConfig AAAconf, boolean delete) {
531         // Validation check
532         if (!AAAconf.isValid()) {
533             String msg = "Invalid Server configuration";
534             logger.warn(msg);
535             return new Status(StatusCode.BADREQUEST, msg);
536         }
537
538         // Update configuration database
539         if (delete) {
540             remoteServerConfigList.remove(AAAconf.getAddress());
541         } else {
542             remoteServerConfigList.put(AAAconf.getAddress(), AAAconf);
543         }
544
545         return new Status(StatusCode.SUCCESS);
546     }
547
548     private Status addRemoveAuthInfo(AuthorizationConfig AAAconf, boolean delete) {
549         Status configCheck = AAAconf.validate();
550         if (!configCheck.isSuccess()) {
551             String msg = "Invalid Authorization configuration: "
552                     + configCheck.getDescription();
553             logger.warn(msg);
554             return new Status(StatusCode.BADREQUEST, msg);
555         }
556
557         // Update configuration database
558         if (delete) {
559             authorizationConfList.remove(AAAconf.getUser());
560         } else {
561             authorizationConfList.put(AAAconf.getUser(), AAAconf);
562         }
563
564         return new Status(StatusCode.SUCCESS);
565     }
566
567     @Override
568     public Status addLocalUser(UserConfig AAAconf) {
569         return addRemoveLocalUser(AAAconf, false);
570     }
571
572     @Override
573     public Status removeLocalUser(UserConfig AAAconf) {
574         return addRemoveLocalUser(AAAconf, true);
575     }
576
577     @Override
578     public Status removeLocalUser(String userName) {
579         if (userName == null || userName.trim().isEmpty()) {
580             return new Status(StatusCode.BADREQUEST, "Invalid user name");
581         }
582
583         if (!localUserConfigList.containsKey(userName)) {
584             return new Status(StatusCode.NOTFOUND, "User does not exist");
585         }
586
587         return addRemoveLocalUser(localUserConfigList.get(userName), true);
588     }
589
590     @Override
591     public Status addAAAServer(ServerConfig AAAconf) {
592         return addRemoveAAAServer(AAAconf, false);
593     }
594
595     @Override
596     public Status removeAAAServer(ServerConfig AAAconf) {
597         return addRemoveAAAServer(AAAconf, true);
598     }
599
600     @Override
601     public Status addAuthInfo(AuthorizationConfig AAAconf) {
602         return addRemoveAuthInfo(AAAconf, false);
603     }
604
605     @Override
606     public Status removeAuthInfo(AuthorizationConfig AAAconf) {
607         return addRemoveAuthInfo(AAAconf, true);
608     }
609
610     @Override
611     public List<UserConfig> getLocalUserList() {
612         return new ArrayList<UserConfig>(localUserConfigList.values());
613     }
614
615     @Override
616     public List<ServerConfig> getAAAServerList() {
617         return new ArrayList<ServerConfig>(remoteServerConfigList.values());
618     }
619
620     @Override
621     public List<AuthorizationConfig> getAuthorizationList() {
622         return new ArrayList<AuthorizationConfig>(
623                 authorizationConfList.values());
624     }
625
626     @Override
627     public Status changeLocalUserPassword(String user, String curPassword, String newPassword) {
628         UserConfig targetConfigEntry = null;
629
630         // update configuration entry
631         targetConfigEntry = localUserConfigList.get(user);
632         if (targetConfigEntry == null) {
633             return new Status(StatusCode.NOTFOUND, "User not found");
634         }
635         Status status = targetConfigEntry.update(curPassword, newPassword, null);
636         if (!status.isSuccess()) {
637             return status;
638         }
639         // Trigger cluster update
640         localUserConfigList.put(user, targetConfigEntry);
641
642         logger.info("Password changed for User \"{}\"", user);
643
644         return status;
645     }
646
647     @Override
648     public void userLogout(String userName) {
649         // TODO: if user was authenticated through AAA server, send
650         // Acct-Status-Type=stop message to server with logout as reason
651         removeUserFromActiveList(userName);
652         logger.info("User \"{}\" logged out", userName);
653     }
654
655     /*
656      * This function will get called by http session mgr when session times out
657      */
658     @Override
659     public void userTimedOut(String userName) {
660         // TODO: if user was authenticated through AAA server, send
661         // Acct-Status-Type=stop message to server with timeout as reason
662         removeUserFromActiveList(userName);
663         logger.info("User \"{}\" timed out", userName);
664     }
665
666     @Override
667     public String getAccessDate(String user) {
668         return this.activeUsers.get(user).getAccessDate();
669     }
670
671     @Override
672     public synchronized Map<String, List<String>> getUserLoggedIn() {
673         Map<String, List<String>> loggedInList = new HashMap<String, List<String>>();
674         for (Map.Entry<String, AuthenticatedUser> user : activeUsers.entrySet()) {
675             String userNameShow = user.getKey();
676             loggedInList.put(userNameShow, user.getValue().getUserRoles());
677         }
678         return loggedInList;
679     }
680
681     public void _umAddUser(CommandInterpreter ci) {
682         String userName = ci.nextArgument();
683         String password = ci.nextArgument();
684         String role = ci.nextArgument();
685
686         List<String> roles = new ArrayList<String>();
687         while (role != null) {
688             if (!role.trim().isEmpty()) {
689                 roles.add(role);
690             }
691             role = ci.nextArgument();
692         }
693
694         if (userName == null || userName.trim().isEmpty() || password == null || password.trim().isEmpty()
695                 || roles.isEmpty()) {
696             ci.println("Invalid Arguments");
697             ci.println("umAddUser <user_name> <password> <user_role>");
698             return;
699         }
700         ci.print(this.addLocalUser(new UserConfig(userName, password, roles)));
701     }
702
703     public void _umRemUser(CommandInterpreter ci) {
704         String userName = ci.nextArgument();
705
706         if (userName == null || userName.trim().isEmpty()) {
707             ci.println("Invalid Arguments");
708             ci.println("umRemUser <user_name>");
709             return;
710         }
711         UserConfig target = localUserConfigList.get(userName);
712         if (target == null) {
713             ci.println("User not found");
714             return;
715         }
716         ci.println(this.removeLocalUser(target));
717     }
718
719     public void _umGetUsers(CommandInterpreter ci) {
720         for (UserConfig conf : this.getLocalUserList()) {
721             ci.println(conf.getUser() + " " + conf.getRoles());
722         }
723     }
724
725     public void _addAAAServer(CommandInterpreter ci) {
726         String server = ci.nextArgument();
727         String secret = ci.nextArgument();
728         String protocol = ci.nextArgument();
729
730         if (server == null || secret == null || protocol == null) {
731             ci.println("Usage : addAAAServer <server> <secret> <protocol>");
732             return;
733         }
734         ServerConfig s = new ServerConfig(server, secret, protocol);
735         addAAAServer(s);
736     }
737
738     public void _removeAAAServer(CommandInterpreter ci) {
739         String server = ci.nextArgument();
740         String secret = ci.nextArgument();
741         String protocol = ci.nextArgument();
742
743         if (server == null || secret == null || protocol == null) {
744             ci.println("Usage : addAAAServer <server> <secret> <protocol>");
745             return;
746         }
747         ServerConfig s = new ServerConfig(server, secret, protocol);
748         removeAAAServer(s);
749     }
750
751     public void _printAAAServers(CommandInterpreter ci) {
752         for (ServerConfig aaaServer : remoteServerConfigList.values()) {
753             ci.println(aaaServer.getAddress() + "-" + aaaServer.getProtocol());
754         }
755     }
756
757     @Override
758     public String getHelp() {
759         StringBuffer help = new StringBuffer();
760         return help.toString();
761     }
762
763     void setClusterGlobalService(IClusterGlobalServices s) {
764         logger.debug("Cluster Service Global set");
765         this.clusterGlobalService = s;
766     }
767
768     void unsetClusterGlobalService(IClusterGlobalServices s) {
769         if (this.clusterGlobalService == s) {
770             logger.debug("Cluster Service Global removed!");
771             this.clusterGlobalService = null;
772         }
773     }
774
775     void unsetContainerAuthClient(IContainerAuthorization s) {
776         if (this.containerAuthorizationClient == s) {
777             this.containerAuthorizationClient = null;
778         }
779     }
780
781     void setContainerAuthClient(IContainerAuthorization s) {
782         this.containerAuthorizationClient = s;
783     }
784
785     void setAppAuthClient(IResourceAuthorization s) {
786         this.applicationAuthorizationClients.add(s);
787     }
788
789     void unsetAppAuthClient(IResourceAuthorization s) {
790         this.applicationAuthorizationClients.remove(s);
791     }
792
793     /**
794      * Function called by the dependency manager when all the required
795      * dependencies are satisfied
796      *
797      */
798     void init() {
799     }
800
801     /**
802      * Function called by the dependency manager when at least one dependency
803      * become unsatisfied or when the component is shutting down because for
804      * example bundle is being stopped.
805      *
806      */
807     void destroy() {
808     }
809
810     /**
811      * Function called by dependency manager after "init ()" is called and after
812      * the services provided by the class are registered in the service registry
813      *
814      */
815     void start() {
816         authProviders = new ConcurrentHashMap<String, IAAAProvider>();
817         // Instantiate cluster synced variables
818         allocateCaches();
819         retrieveCaches();
820
821         // Read startup configuration and populate databases
822         loadConfigurations();
823
824         // Check if a password recovery was triggered for default network admin user
825         checkPasswordRecovery();
826
827         // Make sure default Network Admin account is there
828         checkDefaultNetworkAdmin();
829
830         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
831         bundleContext.registerService(CommandProvider.class.getName(), this, null);
832     }
833
834     /**
835      * Function called by the dependency manager before the services exported by
836      * the component are unregistered, this will be followed by a "destroy ()"
837      * calls
838      *
839      */
840     void stop() {
841     }
842
843     @Override
844     public List<String> getUserRoles(String userName) {
845         List<String> roles = null;
846         if (userName != null) {
847             /*
848              * First look in active users then in local configured users,
849              * finally in local authorized users
850              */
851             if (activeUsers.containsKey(userName)) {
852                 roles = activeUsers.get(userName).getUserRoles();
853             } else if (localUserConfigList.containsKey(userName)) {
854                 roles = localUserConfigList.get(userName).getRoles();
855             } else if (authorizationConfList.containsKey(userName)) {
856                 roles = authorizationConfList.get(userName).getRoles();
857             }
858         }
859         return (roles == null) ? new ArrayList<String>(0) : roles;
860     }
861
862     @Override
863     public UserLevel getUserLevel(String username) {
864         // Returns the highest controller user level for the passed user
865         List<String> rolesNames = getUserRoles(username);
866
867         if (rolesNames.isEmpty()) {
868             return UserLevel.NOUSER;
869         }
870
871         // Check against the well known controller roles first
872         if (rolesNames.contains(UserLevel.SYSTEMADMIN.toString())) {
873             return UserLevel.SYSTEMADMIN;
874         }
875         if (rolesNames.contains(UserLevel.NETWORKADMIN.toString())) {
876             return UserLevel.NETWORKADMIN;
877         }
878         if (rolesNames.contains(UserLevel.NETWORKOPERATOR.toString())) {
879             return UserLevel.NETWORKOPERATOR;
880         }
881         // Check if container user now
882         if (containerAuthorizationClient != null) {
883             for (String roleName : rolesNames) {
884                 if (containerAuthorizationClient.isApplicationRole(roleName)) {
885                     return UserLevel.CONTAINERUSER;
886                 }
887             }
888         }
889         // Finally check if application user
890         if (applicationAuthorizationClients != null) {
891             for (String roleName : rolesNames) {
892                 for (IResourceAuthorization client : this.applicationAuthorizationClients) {
893                     if (client.isApplicationRole(roleName)) {
894                         return UserLevel.APPUSER;
895                     }
896                 }
897             }
898         }
899         return UserLevel.NOUSER;
900     }
901
902
903     @Override
904     public List<UserLevel> getUserLevels(String username) {
905         // Returns the controller user levels for the passed user
906         List<String> rolesNames =  getUserRoles(username);
907         List<UserLevel> levels = new ArrayList<UserLevel>();
908
909         if (rolesNames.isEmpty()) {
910             return levels;
911         }
912
913         // Check against the well known controller roles first
914         if (rolesNames.contains(UserLevel.SYSTEMADMIN.toString())) {
915             levels.add(UserLevel.SYSTEMADMIN);
916         }
917         if (rolesNames.contains(UserLevel.NETWORKADMIN.toString())) {
918             levels.add(UserLevel.NETWORKADMIN);
919         }
920         if (rolesNames.contains(UserLevel.NETWORKOPERATOR.toString())) {
921             levels.add(UserLevel.NETWORKOPERATOR);
922         }
923         // Check if container user now
924         if (containerAuthorizationClient != null) {
925             for (String roleName : rolesNames) {
926                 if (containerAuthorizationClient.isApplicationRole(roleName)) {
927                     levels.add(UserLevel.CONTAINERUSER);
928                     break;
929                 }
930             }
931         }
932         // Finally check if application user
933         if (applicationAuthorizationClients != null) {
934             for (String roleName : rolesNames) {
935                 for (IResourceAuthorization client : this.applicationAuthorizationClients) {
936                     if (client.isApplicationRole(roleName)) {
937                         levels.add(UserLevel.APPUSER);
938                         break;
939                     }
940                 }
941             }
942         }
943         return levels;
944     }
945
946     @Override
947     public Status saveConfiguration() {
948         boolean success = true;
949         Status ret = saveLocalUserList();
950         if (!ret.isSuccess()) {
951             success = false;
952         }
953         ret = saveAAAServerList();
954         if (!ret.isSuccess()) {
955             success = false;
956         }
957         ret = saveAuthorizationList();
958         if (!ret.isSuccess()) {
959             success = false;
960         }
961
962         if (success) {
963             return new Status(StatusCode.SUCCESS);
964         }
965
966         return new Status(StatusCode.INTERNALERROR, "Failed to save user configurations");
967     }
968
969     @Override
970     public UserDetails loadUserByUsername(String username)
971             throws UsernameNotFoundException {
972         AuthenticatedUser user = activeUsers.get(username);
973
974         if (user != null) {
975             boolean enabled = true;
976             boolean accountNonExpired = true;
977             boolean credentialsNonExpired = true;
978             boolean accountNonLocked = true;
979
980             return new User(username, localUserConfigList.get(username)
981                     .getPassword(), enabled, accountNonExpired,
982                     credentialsNonExpired, accountNonLocked,
983                     user.getGrantedAuthorities(getUserLevel(username)));
984         } else {
985             throw new UsernameNotFoundException("User not found " + username);
986         }
987     }
988
989     @Override
990     public boolean supports(Class<?> authentication) {
991         return UsernamePasswordAuthenticationToken.class
992                 .isAssignableFrom(authentication);
993
994     }
995
996     @Override
997     public SecurityContextRepository getSecurityContextRepo() {
998         return securityContextRepo;
999     }
1000
1001     public void setSecurityContextRepo(
1002             SecurityContextRepository securityContextRepo) {
1003         this.securityContextRepo = securityContextRepo;
1004     }
1005
1006     @Override
1007     public Authentication authenticate(Authentication authentication)
1008             throws AuthenticationException {
1009
1010         if (StringUtils.isBlank((String) authentication.getCredentials())
1011                 || StringUtils.isBlank((String) authentication.getPrincipal())) {
1012             throw new BadCredentialsException(
1013                     "Username or credentials did not match");
1014         }
1015
1016         AuthResultEnum result = authenticate(
1017                 (String) authentication.getPrincipal(),
1018                 (String) authentication.getCredentials());
1019         if (result.equals(AuthResultEnum.AUTHOR_PASS)
1020                 || result.equals(AuthResultEnum.AUTH_ACCEPT_LOC)
1021                 || result.equals(AuthResultEnum.AUTH_ACCEPT)) {
1022
1023             AuthenticatedUser user = activeUsers.get(authentication
1024                     .getPrincipal().toString());
1025
1026             if (user == null) {
1027                 throw new AuthenticationServiceException(
1028                         "Authentication Failure");
1029             }
1030
1031             authentication = new UsernamePasswordAuthenticationToken(
1032                     authentication.getPrincipal(),
1033                     authentication.getCredentials(),
1034                     user.getGrantedAuthorities(getUserLevel(authentication
1035                             .getName())));
1036             return authentication;
1037
1038         } else {
1039             throw new BadCredentialsException(
1040                     "Username or credentials did not match");
1041         }
1042
1043     }
1044
1045     // Following are setters for use in unit testing
1046     void setLocalUserConfigList(ConcurrentMap<String, UserConfig> ucl) {
1047         if (ucl != null) {
1048             this.localUserConfigList = ucl;
1049         }
1050     }
1051
1052     void setRemoteServerConfigList(ConcurrentMap<String, ServerConfig> scl) {
1053         if (scl != null) {
1054             this.remoteServerConfigList = scl;
1055         }
1056     }
1057
1058     void setAuthorizationConfList(ConcurrentMap<String, AuthorizationConfig> acl) {
1059         if (acl != null) {
1060             this.authorizationConfList = acl;
1061         }
1062     }
1063
1064     void setActiveUsers(ConcurrentMap<String, AuthenticatedUser> au) {
1065         if (au != null) {
1066             this.activeUsers = au;
1067         }
1068     }
1069
1070     void setAuthProviders(ConcurrentMap<String, IAAAProvider> ap) {
1071         if (ap != null) {
1072             this.authProviders = ap;
1073         }
1074     }
1075
1076     @Override
1077     public ISessionManager getSessionManager() {
1078         return this.sessionMgr;
1079     }
1080
1081     public void setSessionMgr(ISessionManager sessionMgr) {
1082         this.sessionMgr = sessionMgr;
1083     }
1084
1085     @Override
1086     public String getPassword(String username) {
1087         return localUserConfigList.get(username).getPassword();
1088     }
1089
1090     @Override
1091     public boolean isRoleInUse(String role) {
1092         if (role == null || role.isEmpty()) {
1093             return false;
1094         }
1095         // Check against controller roles
1096         if (role.equals(UserLevel.SYSTEMADMIN.toString())
1097                 || role.equals(UserLevel.NETWORKADMIN.toString())
1098                 || role.equals(UserLevel.NETWORKOPERATOR.toString())) {
1099             return true;
1100         }
1101         // Check if container roles
1102         if (containerAuthorizationClient != null) {
1103             if (containerAuthorizationClient.isApplicationRole(role)) {
1104                 return true;
1105             }
1106         }
1107         // Finally if application role
1108         if (applicationAuthorizationClients != null) {
1109             for (IResourceAuthorization client : this.applicationAuthorizationClients) {
1110                 if (client.isApplicationRole(role)) {
1111                     return true;
1112                 }
1113             }
1114         }
1115         return false;
1116     }
1117 }