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