001/* 002 * Copyright 2023 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.right; 017 018import java.util.ArrayList; 019import java.util.Comparator; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Map.Entry; 025import java.util.Objects; 026import java.util.Set; 027 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030 031import org.ametys.core.right.AccessController.ExplanationObject; 032import org.ametys.core.right.AccessController.Permission; 033import org.ametys.core.ui.Callable; 034import org.ametys.core.ui.StaticClientSideElement; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.core.user.UserManager; 037import org.ametys.plugins.core.user.UserHelper; 038import org.ametys.runtime.i18n.I18nizableText; 039 040/** 041 * Client side element of the tool displaying all the permissions for a given user 042 */ 043public class UserPermissionsToolClientSideElement extends StaticClientSideElement 044{ 045 046 private UserHelper _userHelper; 047 private UserManager _userManager; 048 private RightProfilesDAO _profileDAO; 049 private RightsExtensionPoint _rightsEP; 050 051 @Override 052 public void service(ServiceManager manager) throws ServiceException 053 { 054 super.service(manager); 055 _profileDAO = (RightProfilesDAO) manager.lookup(RightProfilesDAO.ROLE); 056 _rightsEP = (RightsExtensionPoint) manager.lookup(RightsExtensionPoint.ROLE); 057 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 058 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 059 } 060 061 /** 062 * Provided a user identity, this method will retrieve all permissions concerning this user 063 * ie permissions for anonymous, any connected user, user's groups, and the user itself 064 * @param login the user login 065 * @param populationId the user population 066 * @return a map with the key "data" containing the list of all the contexts and their permissions. 067 * And a key metaData containing a map used to reconfigure the store calling the callable 068 * 069 * The list of context is something like : 070 * [ 071 * { 072 * label: "foo", 073 * category: "bar", 074 * order: 0, 075 * <permissionKey>: { 076 * assignments: [accessResultInfo,…] 077 * accessResult: accessResult, 078 * } 079 * } 080 * ] 081 */ 082 @Callable(rights = "Runtime_Rights_SeeUserProfiles") 083 public Map<String, Object> getUserPermissions(String login, String populationId) 084 { 085 List<Map<String, Object>> result = new ArrayList<>(); 086 087 UserIdentity user = new UserIdentity(login, populationId); 088 089 Map<ExplanationObject, Map<Permission, List<AccessExplanation>>> permissionsForUser = _rightManager.getAllPermissions(user); 090 091 if (permissionsForUser.isEmpty()) 092 { 093 return Map.of(); 094 } 095 096 Set<Permission> allPermissions = new HashSet<>(); 097 098 for (ExplanationObject context: permissionsForUser.keySet()) 099 { 100 allPermissions.addAll(permissionsForUser.get(context).keySet()); 101 102 Map<String, Object> jsonAssignments = _contextPermissionsToJSON(permissionsForUser.get(context)); 103 104 jsonAssignments.put("label", context.label()); 105 jsonAssignments.put("category", context.category()); 106 jsonAssignments.put("order", context.order()); 107 108 result.add(jsonAssignments); 109 } 110 111 List<Map<String, Object>> jsonPermissions = allPermissions.stream() 112 .map(this::_permissionToJSON) 113 .filter(Objects::nonNull) 114 .toList(); 115 116 return Map.of( 117 "data", result, 118 "metaData", Map.of( 119 "permissions", jsonPermissions 120 ) 121 ); 122 } 123 124 /** 125 * Take a map associating permissions with a list of explanations 126 * and serialize it into a JSON object organized by permission, 127 * storing the resulting access result for this permission 128 * and the list of each access explanation 129 * { 130 * profile1 : { 131 * accessResult: <the merge result of all the AccessResult targeting the profile> 132 * assignments: [ 133 * { 134 * accessResult: … 135 * target: … 136 * }, 137 * … 138 * ] 139 * },… 140 * @param contextPermissions a map of all the permissions on a context 141 * @return a JSON object representing those permissions 142 */ 143 private Map<String, Object> _contextPermissionsToJSON(Map<Permission, List<AccessExplanation>> contextPermissions) 144 { 145 // assignments are now organized the way we want for the result 146 // we now need to JSONify it 147 Map<String, Object> result = new HashMap<>(); 148 for (Entry<Permission, List<AccessExplanation>> entry : contextPermissions.entrySet()) 149 { 150 List<AccessExplanation> explanations = entry.getValue(); 151 if (!explanations.isEmpty()) 152 { 153 // sort to have user > group > any connected > anonymous 154 explanations.sort(Comparator.naturalOrder()); 155 156 Permission permission = entry.getKey(); 157 result.put( 158 permission.toString(), 159 Map.of( 160 "accessResult", explanations.get(0).accessResult(), // list is sorted so first item is merge result 161 "accessExplanations", explanations 162 ) 163 ); 164 } 165 } 166 return result; 167 } 168 169 /** 170 * Get user's information 171 * @param login The user's login 172 * @param populationId The id of the population 173 * @return The user's information 174 */ 175 @Callable(rights = "Runtime_Rights_SeeUserProfiles") 176 public Map<String, Object> getUser (String login, String populationId) 177 { 178 return _userHelper.user2json(_userManager.getUser(populationId, login), true); 179 } 180 181 private Map<String, Object> _permissionToJSON(Permission permission) 182 { 183 switch (permission.type()) 184 { 185 case READ: 186 return Map.of( 187 "key", permission.toString(), 188 "type", permission.type().name(), 189 "label", new I18nizableText("plugin.core", "PLUGINS_CORE_RIGHTS_READER_LABEL"), 190 "rights", List.of() 191 ); 192 case ALL_RIGHTS: 193 return Map.of( 194 "key", permission.toString(), 195 "type", permission.type().name(), 196 "label", new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_TOOL_USER_PROFILES_ALL_RIGHTS_COLUMN_LABEL"), 197 "rights", List.of() 198 ); 199 case PROFILE: 200 Profile profile = _profileDAO.getProfile(permission.id()); 201 if (profile != null) 202 { 203 return Map.of( 204 "key", permission.toString(), 205 "id", permission.id(), 206 "type", permission.type().name(), 207 "label", profile.getLabel(), 208 "rights", _profileDAO.getRights(permission.id()) 209 ); 210 } 211 else // ignore unknown profiles 212 { 213 getLogger().info("No profile with id '" + permission.id() + "'. The permission is ignored."); 214 return null; 215 } 216 case RIGHT: 217 Right right = _rightsEP.getExtension(permission.id()); 218 if (right != null) 219 { 220 return Map.of( 221 "key", permission.toString(), 222 "id", permission.id(), 223 "type", permission.type().name(), 224 "label", right.getLabel(), 225 "rights", List.of(permission.id()) 226 ); 227 } 228 else // ignore unknown rights 229 { 230 getLogger().info("No right with id '" + permission.id() + "'. The permission is ignored."); 231 return null; 232 } 233 default: 234 return null; 235 } 236 } 237 238}