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.security;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.restlet.Application;
29  import org.restlet.security.Group;
30  import org.restlet.security.Role;
31  import org.restlet.security.User;
32  
33  import fr.cnes.doi.application.AdminApplication;
34  import fr.cnes.doi.application.DoiMdsApplication;
35  import fr.cnes.doi.db.AbstractUserRoleDBHelper;
36  import fr.cnes.doi.db.MyMemoryRealm;
37  import fr.cnes.doi.db.model.DOIProject;
38  import fr.cnes.doi.exception.DoiRuntimeException;
39  import fr.cnes.doi.logging.business.JsonMessage;
40  import fr.cnes.doi.db.model.DOIUser;
41  import fr.cnes.doi.exception.DOIDbException;
42  import fr.cnes.doi.plugin.PluginFactory;
43  import fr.cnes.doi.utils.UniqueProjectName;
44  import fr.cnes.doi.utils.spec.Requirement;
45  
46  /**
47   * Security class for authentication by REALM.
48   *
49   * @author Jean-Christophe Malapert (jean-christophe.malapert@cnes.fr)
50   */
51  @Requirement(reqId = Requirement.DOI_AUTH_010, reqName = Requirement.DOI_AUTH_010_NAME)
52  public final class RoleAuthorizer {
53  
54      /**
55       * Role name for the administrators {@value #ROLE_ADMIN}.
56       */
57      public static final String ROLE_ADMIN = "admin";
58  
59      /**
60       * Group name for the users {@value #GROUP_USERS}.
61       */
62      public static final String GROUP_USERS = "Users";
63  
64      /**
65       * Group name for the administrators {@value #GROUP_ADMIN}.
66       */
67      public static final String GROUP_ADMIN = "Administrator";
68  
69      /**
70       * Logger.
71       */
72      private static final Logger LOG = LogManager.getLogger(RoleAuthorizer.class.getName());
73  
74      /**
75       * Realm.
76       */
77      private static final MyMemoryRealm REALM = PluginFactory.getUserManagement().getRealm();
78  
79      /**
80       * Access to unique INSTANCE of role authorizer
81       *
82       * @return the configuration instance.
83       */
84      public static RoleAuthorizer getInstance() {
85          return RoleAuthorizerHolder.INSTANCE;
86      }
87  
88      /**
89       * Constructor.
90       */
91      private RoleAuthorizer() {
92          initUsersGroups();
93      }
94  
95      /**
96       * Init users and groups in REALM.
97       */
98      private void initUsersGroups() {
99          LOG.traceEntry();
100 
101         // Add users
102         LOG.debug("Add users to REALM");
103         final AbstractUserRoleDBHelper manageUsers = PluginFactory.getUserManagement();
104         List<DOIUser> doiUsers;
105         try {
106             doiUsers = manageUsers.getUsers();
107         } catch (DOIDbException ex) {
108             doiUsers = new ArrayList<>();
109         }
110         final List<User> users = new ArrayList<>();
111         final List<User> admins = new ArrayList<>();
112         for (final DOIUser doiUser : doiUsers) {
113             final User user = new User(doiUser.getUsername());
114 
115             // Create list of user
116             users.add(user);
117 
118             // Create list of admin
119             if (doiUser.isAdmin()) {
120                 admins.add(user);
121             }
122         }
123         RoleAuthorizer.REALM.setUsers(users);
124         LOG.debug("List of users in realm : {}", RoleAuthorizer.REALM.getUsers());
125 
126         // Add Groups       
127         final Group administrators = new Group(GROUP_ADMIN, "Administrators");
128         LOG.debug("Add users to Administrators group");
129         administrators.getMemberUsers().addAll(admins);
130         LOG.debug("List of users in Administrators group {}", administrators.getMemberUsers());
131 
132         if (!RoleAuthorizer.REALM.getRootGroups().contains(administrators)) {
133             LOG.debug("Add administators group to rootGroups in REALM");
134             RoleAuthorizer.REALM.getRootGroups().add(administrators);
135         }
136         LOG.traceExit();
137     }
138 
139     /**
140      * Sets Realm to Mds application.
141      *
142      * @param app Mds application
143      */
144     private void initForMds(final Application app) {
145         LOG.traceEntry(new JsonMessage(app));
146         
147         // we load projects from database
148         List<DOIProject> projects;
149         try {
150             projects = UniqueProjectName.getInstance().getProjects();
151         } catch (DOIDbException ex) {
152             projects = new ArrayList<>();
153         }
154         final AbstractUserRoleDBHelper manageUsers = PluginFactory.getUserManagement();
155         LOG.debug("{} projects have already been registered", projects.size());
156         for (final DOIProject project : projects) {
157             // for each project, create a role as the project name
158             final Integer projectID = project.getSuffix();
159             final Role role = new Role(app, String.valueOf(projectID), "Role " + String.valueOf(
160                     projectID) + " for " + app.getName());
161 
162             // get the users for a role.
163             List<DOIUser> doiUsers;
164             try {
165                 doiUsers = manageUsers.getUsersFromRole(projectID);
166             } catch (DOIDbException ex) {
167                 doiUsers = new ArrayList<>();
168             }
169             final List<User> usersFromProject = new ArrayList<>();
170             for (final DOIUser doiUser : doiUsers) {
171                 final User user = REALM.findUser(doiUser.getUsername());
172                 if (user != null) {
173                     usersFromProject.add(user);
174                 }
175             }
176 
177             // create a role authorizer for each user related to a project
178             for (final User user : usersFromProject) {
179                 LOG.debug("Add user {} to role {} for {}", user, projectID, app.getName());
180                 RoleAuthorizer.REALM.map(user, role);
181             }
182         }
183         
184         // Add the group admin in REALM of MDS
185         // When no project is created, only the group is attached to the 
186         // application. So, in this way, we can retrieve the application from
187         // the REALM to set rights even when no project is created
188         final Group admin = findGroupByName(GROUP_ADMIN);
189         RoleAuthorizer.REALM.map(admin, Role.get(app, ROLE_ADMIN));        
190 
191         app.getContext().setDefaultEnroler(RoleAuthorizer.REALM.getEnroler());
192         app.getContext().setDefaultVerifier(RoleAuthorizer.REALM.getVerifier());
193 
194         LOG.traceExit();
195     }
196 
197     /**
198      * Finds a group by its name
199      *
200      * @param name group name
201      * @return the group
202      */
203     private Group findGroupByName(final String name) {
204         LOG.traceEntry("Parameter : {}", name);
205         final List<Group> groups = RoleAuthorizer.REALM.getRootGroups();
206         Group searchedGroup = null;
207         for (final Group group : groups) {
208             LOG.debug("group name : {}", group.getName());
209             if (group.getName().equals(name)) {
210                 searchedGroup = group;
211                 LOG.debug("group found");
212                 break;
213             }
214         }
215         if (searchedGroup == null) {
216             LOG.error("Please, create a group {}", name);
217             throw LOG.throwing(new DoiRuntimeException("Please, create a group " + name));
218         }
219         return LOG.traceExit(searchedGroup);
220     }
221 
222     /**
223      * Sets Realm for admin application.
224      *
225      * @param app Admin application
226      */
227     private void initForAdmin(final Application app) {
228         LOG.traceEntry(new JsonMessage(app));
229         
230         final Group admin = findGroupByName(GROUP_ADMIN);
231         RoleAuthorizer.REALM.map(admin, Role.get(app, ROLE_ADMIN));
232         app.getContext().setDefaultEnroler(RoleAuthorizer.REALM.getEnroler());
233         app.getContext().setDefaultVerifier(RoleAuthorizer.REALM.getVerifier());
234 
235         LOG.traceExit();
236     }
237 
238     /**
239      * Init Realm for an application.
240      *
241      * @param app application
242      * @return True when the realm is initialized otherwise False
243      */
244     public boolean createRealmFor(final Application app) {
245         LOG.traceEntry(new JsonMessage(app));
246 
247         boolean isCreated;
248         switch (app.getName()) {
249             case DoiMdsApplication.NAME:
250                 initForMds(app);
251                 isCreated = true;
252                 LOG.debug("Init for MDS ... done");
253                 break;
254             case AdminApplication.NAME:
255                 initForAdmin(app);
256                 isCreated = true;
257                 LOG.debug("Init for admin ... done");
258                 break;
259             default:
260                 LOG.debug("No Realm is initialized for this application {}", app.getName());
261                 isCreated = false;
262                 break;
263         }
264 
265         return LOG.traceExit(isCreated);
266     }
267 
268     /**
269      * Loads the application
270      *
271      * @param appName application name
272      * @return the application or null if the application is not defined in the
273      * REALM
274      */
275     public Application loadApplicationBy(final String appName) {
276         LOG.traceEntry("Parameters : {}", appName);
277         Application searchedApp = null;
278         final List<Group> groups = RoleAuthorizer.REALM.getRootGroups();                
279         final Iterator<Group> groupIter = groups.iterator();
280         boolean isFound = false;
281         while (groupIter.hasNext() && !isFound) {
282             final Group group = groupIter.next();
283             final Set<Role> roles = RoleAuthorizer.REALM.findRoles(group);
284             final Iterator<Role> roleIter = roles.iterator();
285             while (roleIter.hasNext() && !isFound) {
286                 final Role role = roleIter.next();
287                 final Application app = role.getApplication();
288                 if (app.getName().equals(appName)) {
289                     searchedApp = app;
290                     isFound = true;
291                 }                
292             }
293         }       
294         return LOG.traceExit(searchedApp);
295     }
296 
297     /**
298      * Class to handle the instance
299      *
300      */
301     private static class RoleAuthorizerHolder {
302 
303         /**
304          * Unique Instance unique
305          */
306         private static final RoleAuthorizer INSTANCE = new RoleAuthorizer();
307     }
308 
309 }