View Javadoc

1   /*
2    * Copyright (C) 2017-2019 Centre National d'Etudes Spatiales (CNES).
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 3.0 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17   * MA 02110-1301  USA
18   */
19  package fr.cnes.doi.plugin.impl.db;
20  
21  import fr.cnes.doi.application.DoiMdsApplication;
22  import fr.cnes.doi.db.MyMemoryRealm;
23  import fr.cnes.doi.db.model.DOIUser;
24  import fr.cnes.doi.exception.DOIDbException;
25  import fr.cnes.doi.exception.DoiRuntimeException;
26  import fr.cnes.doi.plugin.AbstractUserRolePluginHelper;
27  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_MAX_ACTIVE_CONNECTIONS;
28  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_MAX_IDLE_CONNECTIONS;
29  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_MIN_IDLE_CONNECTIONS;
30  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_PWD;
31  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_URL;
32  import static fr.cnes.doi.plugin.impl.db.impl.DOIDbDataAccessServiceImpl.DB_USER;
33  import fr.cnes.doi.plugin.impl.db.service.DOIDbDataAccessService;
34  import fr.cnes.doi.plugin.impl.db.service.DatabaseSingleton;
35  import fr.cnes.doi.security.RoleAuthorizer;
36  import fr.cnes.doi.settings.EmailSettings;
37  import fr.cnes.doi.utils.Utils;
38  
39  import java.util.ArrayList;
40  import java.util.Collections;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Set;
45  import java.util.concurrent.ConcurrentHashMap;
46  import org.apache.logging.log4j.LogManager;
47  import org.apache.logging.log4j.Logger;
48  import org.restlet.Application;
49  import org.restlet.security.Role;
50  import org.restlet.security.User;
51  
52  /**
53   * Default implementation of the authentication plugin. This implementation
54   * defines users/groups/roles.
55   *
56   * @author Jean-Christophe Malapert (jean-christophe.malapert@cnes.fr)
57   */
58  public final class DefaultUserRoleImpl extends AbstractUserRolePluginHelper {
59  
60      /**
61       * Plugin description.
62       */
63      private static final String DESCRIPTION = "Provides a pre-defined list of users and groups";
64      /**
65       * Plugin version.
66       */
67      private static final String VERSION = "1.0.0";
68      /**
69       * Plugin owner.
70       */
71      private static final String OWNER = "CNES";
72      /**
73       * Plugin author.
74       */
75      private static final String AUTHOR = "Jean-Christophe Malapert";
76      /**
77       * Plugin license.
78       */
79      private static final String LICENSE = "LGPLV3";
80      /**
81       * Logger.
82       */
83      private static final Logger LOG = LogManager.getLogger(DefaultUserRoleImpl.class.getName());
84      /**
85       * Class name.
86       */
87      private final String NAME = this.getClass().getName();
88  
89      /**
90       * User/Role realm
91       */
92      private final MyMemoryRealm REALM = getRealm();
93  
94      /**
95       * Database access.
96       */
97      private DOIDbDataAccessService das;
98  
99      /**
100      * Configuration file.
101      */
102     private Map<String, String> conf;
103 
104     /**
105      * Status of the plugin configuration.
106      */
107     private boolean configured = false;
108 
109     /**
110      * Options for JDBC.
111      */
112     private final Map<String, Integer> options = new ConcurrentHashMap<>();
113 
114     /**
115      * {@inheritDoc }
116      */
117     @Override
118     public void setConfiguration(final Object configuration) {
119         this.conf = (Map<String, String>) configuration;
120         final String dbUrl = this.conf.get(DB_URL);
121         final String dbUser = this.conf.get(DB_USER);
122         final String dbPwd = this.conf.get(DB_PWD);
123         if (this.conf.containsKey(DB_MIN_IDLE_CONNECTIONS)) {
124             this.options.put(DB_MIN_IDLE_CONNECTIONS,
125                     Integer.valueOf(this.conf.get(DB_MIN_IDLE_CONNECTIONS)));
126         }
127         if (this.conf.containsKey(DB_MAX_IDLE_CONNECTIONS)) {
128             this.options.put(DB_MAX_IDLE_CONNECTIONS,
129                     Integer.valueOf(this.conf.get(DB_MAX_IDLE_CONNECTIONS)));
130         }
131         if (this.conf.containsKey(DB_MAX_ACTIVE_CONNECTIONS)) {
132             this.options.put(DB_MAX_ACTIVE_CONNECTIONS,
133                     Integer.valueOf(this.conf.get(DB_MAX_ACTIVE_CONNECTIONS)));
134         }
135         LOG.info("[CONF] Plugin database URL : {}", dbUrl);
136         LOG.info("[CONF] Plugin database user : {}", dbUser);
137         LOG.info("[CONF] Plugin database password : {}", Utils.transformPasswordToStars(dbPwd));
138         LOG.info("[CONF] Plugin options : {}", options);
139 
140         this.configured = true;
141     }
142 
143     /**
144      * {@inheritDoc }
145      */
146     @Override
147     public void initConnection() throws DoiRuntimeException {
148         DatabaseSingleton.getInstance().init(
149                 this.conf.get(DB_URL), this.conf.get(DB_USER), this.conf.get(DB_PWD), this.options);
150         this.das = DatabaseSingleton.getInstance().getDatabaseAccess();
151     }
152 
153     /**
154      * {@inheritDoc }
155      */
156     @Override
157     public List<DOIUser> getUsers() throws DOIDbException {
158         final List<DOIUser> listUser = new ArrayList<>();
159         listUser.addAll(das.getAllDOIusers());
160         return Collections.unmodifiableList(listUser);
161     }
162 
163     /**
164      * {@inheritDoc }
165      */
166     @Override
167     public List<DOIUser> getUsersFromRole(final int roleName) throws DOIDbException {
168         final List<DOIUser> listUser = new ArrayList<>();
169         listUser.addAll(das.getAllDOIUsersForProject(roleName));
170         return Collections.unmodifiableList(listUser);
171     }
172 
173     /**
174      * {@inheritDoc }
175      */
176     @Override
177     public boolean addUserToRole(final String user, final int role) {
178         boolean isAdded = false;
179         try {
180             das.addDOIProjectToUser(user, role);
181             final Application app = RoleAuthorizer.getInstance().loadApplicationBy(DoiMdsApplication.NAME);
182             
183             LOG.info("The user {} is added to role {} for {}.", user, role,
184                     app.getName());
185 
186             final User userFromRealm = REALM.findUser(user);
187             final Role roleFromRealm = new Role(app, String.valueOf(role),
188                     "Role " + String.valueOf(role) + " for " + app.getName());
189             REALM.map(userFromRealm, roleFromRealm);
190             isAdded = true;
191 
192         } catch (DOIDbException e) {
193             LOG.fatal("An error occured while trying to add user " + user + " to project " + role,
194                     e);
195         }
196         return isAdded;
197     }
198 
199     /**
200      * {@inheritDoc }
201      */
202     @Override
203     public boolean removeUserToRole(final String user, final int role) {
204         boolean isRemoved = false;
205         try {
206             das.removeDOIProjectFromUser(user, role);
207             isRemoved = true;
208             LOG.info("The user {} is removed from role {} for {}.", user, role, Application.
209                     getCurrent().getName());
210 
211             final User userFromRealm = REALM.findUser(user);
212             final Set<Role> rolesFromRealm = REALM.findRoles(userFromRealm);
213             for (final Role r : rolesFromRealm) {
214                 if (r.getName().equals(String.valueOf(role))) {
215                     REALM.unmap(userFromRealm, r);
216                 }
217             }
218 
219         } catch (DOIDbException e) {
220             LOG.fatal("An error occured while trying to remove user " + user + " from project "
221                     + role, e);
222         }
223         return isRemoved;
224     }
225 
226     /**
227      * Sets the user to the admin group.
228      *
229      * @param user username
230      * @throws DOIDbException - if a Database error occurs
231      */
232     private void setUserToAdminGroupInDB(final String user) throws DOIDbException {
233         das.setAdmin(user);
234         LOG.info("The user {} is added to admin group.", user);
235         EmailSettings.getInstance().sendMessage("[DOI] Admin group",
236                 "The user " + user + " has been added to the administror group.");
237         final User userFromRealm = REALM.findUser(user);
238         if (!REALM.getRootGroups().get(0).getMemberUsers().contains(userFromRealm)) {
239             REALM.getRootGroups().get(0).getMemberUsers().add(userFromRealm);
240         }
241     }
242 
243     /**
244      * {@inheritDoc }
245      */
246     @Override
247     public boolean setUserToAdminGroup(final String user) {
248         boolean isSetted = false;
249         try {
250             if (!das.isAdmin(user)) {
251                 setUserToAdminGroupInDB(user);
252                 isSetted = true;
253             }
254         } catch (DOIDbException e) {
255             LOG.fatal("An error occured while trying to add user " + user + " to admin group", e);
256         }
257         return isSetted;
258     }
259 
260     /**
261      * {@inheritDoc }
262      */
263     @Override
264     public boolean unsetUserFromAdminGroup(final String user) {
265         boolean isUnsetted = false;
266         try {
267             das.unsetAdmin(user);
268             isUnsetted = true;
269             LOG.info("The user {} is removed to admin group.", user);
270 
271             EmailSettings.getInstance().sendMessage("[DOI] Admin group",
272                     "The user " + user + " has been removed from the administrator group.");
273 
274             final User userFromRealm = REALM.findUser(user);
275             if (REALM.getRootGroups().get(0).getMemberUsers().contains(userFromRealm)) {
276                 REALM.getRootGroups().get(0).getMemberUsers().remove(userFromRealm);
277             }
278 
279         } catch (DOIDbException e) {
280             LOG.fatal("An error occured while trying to remove user " + user + " to admin group",
281                     e);
282         }
283         return isUnsetted;
284     }
285 
286     /**
287      * {@inheritDoc }
288      */
289     @Override
290     public boolean isUserExist(final String username) {
291         boolean isExist = false;
292         try {
293             isExist = das.isUserExist(username);
294         } catch (DOIDbException e) {
295             LOG.fatal("An error occured while trying to know if user " + username + " exist", e);
296         }
297         return isExist;
298     }
299 
300     /**
301      * {@inheritDoc }
302      */
303     @Override
304     public boolean addDOIUser(final String username, final Boolean admin) {
305         boolean isAdded;
306         try {
307             this.das.addDOIUser(username, admin);
308             if (REALM.findUser(username) == null) {
309                 REALM.getUsers().add(new User(username));
310             }
311             isAdded = true;
312             LOG.info("The user {} is added to database.", username);
313         } catch (DOIDbException ex) {
314             isAdded = false;
315             LOG.fatal("Cannot add the user {}", username);
316         }
317         return isAdded;
318     }
319 
320     /**
321      * {@inheritDoc }
322      */
323     @Override
324     public boolean addDOIUser(final String username, final Boolean admin, final String email) {
325         boolean isAdded;
326         try {
327             this.das.addDOIUser(username, admin, email);
328             if (REALM.findUser(username) == null) {
329                 REALM.getUsers().add(new User(username));
330             }
331             isAdded = true;
332             LOG.info("The user {} is added to database.", username);
333         } catch (DOIDbException ex) {
334             isAdded = false;
335             LOG.fatal("Cannot add the user {}", username);
336         }
337         return isAdded;
338     }
339 
340     /**
341      * {@inheritDoc }
342      */
343     @Override
344     public boolean removeDOIUser(final String username) {
345         boolean isRemoved;
346         try {
347             this.das.removeDOIUser(username);
348             final User userFromRealm = REALM.findUser(username);
349             if (userFromRealm != null) {
350                 REALM.getUsers().remove(userFromRealm);
351             }
352             isRemoved = true;
353             LOG.info("The user {} is removed from database.", username);
354         } catch (DOIDbException ex) {
355             isRemoved = false;
356             LOG.fatal("Cannot remove user" + username, ex);
357         }
358         return isRemoved;
359     }
360 
361     /**
362      * {@inheritDoc }
363      */
364     @Override
365     public String getName() {
366         return NAME;
367     }
368 
369     /**
370      * {@inheritDoc }
371      */
372     @Override
373     public String getDescription() {
374         return DESCRIPTION;
375     }
376 
377     /**
378      * {@inheritDoc }
379      */
380     @Override
381     public String getVersion() {
382         return VERSION;
383     }
384 
385     /**
386      * {@inheritDoc }
387      */
388     @Override
389     public String getAuthor() {
390         return AUTHOR;
391     }
392 
393     /**
394      * {@inheritDoc }
395      */
396     @Override
397     public String getOwner() {
398         return OWNER;
399     }
400 
401     /**
402      * {@inheritDoc }
403      */
404     @Override
405     public String getLicense() {
406         return LICENSE;
407     }
408 
409     /**
410      * {@inheritDoc}
411      */
412     @Override
413     public StringBuilder validate() {
414         final StringBuilder validation = new StringBuilder();
415         final String message = "Sets ";
416         if (!this.conf.containsKey(DB_URL)) {
417             validation.append(message).append(DB_URL).append("\n");
418         }
419         return validation;
420     }
421 
422     /**
423      * Checks if the keyword is a password.
424      *
425      * @param key keyword to check
426      * @return True when the keyword is a password otherwise False
427      */
428     public static boolean isPassword(final String key) {
429         return DB_PWD.equals(key);
430     }
431 
432     /**
433      * {@inheritDoc}
434      */
435     @Override
436     public void release() {
437         final List<User> users = REALM.getUsers();
438         // we unmap all roles for each user
439         for (final User user : users) {
440             final Set<Role> roles = REALM.findRoles(user);
441             final Iterator<Role> roleIter = roles.iterator();
442             while (roleIter.hasNext()) {
443                 final Role role = roleIter.next();
444                 REALM.unmap(user, role);
445             }
446         }
447         try {
448             if (this.das != null) {
449                 this.das.close();
450             }
451         } catch (DOIDbException ex) {
452         }
453         this.configured = false;
454     }
455 
456     /**
457      * {@inheritDoc}
458      */
459     @Override
460     public boolean isConfigured() {
461         return this.configured;
462     }
463 }