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