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