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