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