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