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