001/* 002 * Copyright 2021 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.plugins.exchange; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.stream.Collectors; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.commons.collections.CollectionUtils; 025import org.apache.commons.lang3.StringUtils; 026 027import org.ametys.core.user.User; 028import org.ametys.core.user.UserIdentity; 029import org.ametys.core.user.UserManager; 030import org.ametys.core.user.directory.UserDirectory; 031import org.ametys.core.user.population.UserPopulation; 032import org.ametys.plugins.messagingconnector.AbstractMessagingConnector; 033import org.ametys.plugins.messagingconnector.CalendarEvent; 034import org.ametys.plugins.messagingconnector.EmailMessage; 035import org.ametys.plugins.messagingconnector.MessagingConnectorException; 036import org.ametys.runtime.config.Config; 037 038/** 039 * The connector used by the messaging connector plugin when the exchange mail server is used. 040 */ 041public class ExchangeConnector extends AbstractMessagingConnector 042{ 043 private UserManager _userManager; 044 045 private EWSConnector _ewsConnector; 046 private GraphConnector _graphConnector; 047 048 private List<String> _ewsUserDirectoryIds; 049 private List<String> _graphUserDirectoryIds; 050 051 @Override 052 public void service(ServiceManager manager) throws ServiceException 053 { 054 super.service(manager); 055 056 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 057 _ewsConnector = (EWSConnector) manager.lookup(EWSConnector.INNER_ROLE); 058 _graphConnector = (GraphConnector) manager.lookup(GraphConnector.INNER_ROLE); 059 } 060 061 @Override 062 public void initialize() 063 { 064 super.initialize(); 065 066 List<String> allowedUserDirectoryIds = null; 067 try 068 { 069 allowedUserDirectoryIds = _getAllowedUserDirectoryIds(List.of()); 070 071 } 072 catch (MessagingConnectorException e) 073 { 074 getLogger().error("An error occured during computation of allowed user directories", e); 075 return; 076 } 077 078 _ewsUserDirectoryIds = new ArrayList<>(); 079 _graphUserDirectoryIds = new ArrayList<>(); 080 081 Boolean ews = Config.getInstance().getValue("org.ametys.plugins.exchange.ews"); 082 Boolean graph = Config.getInstance().getValue("org.ametys.plugins.exchange.graph"); 083 084 085 if (ews) 086 { 087 String userDirectoryIdsAsString = Config.getInstance().getValue("org.ametys.plugins.exchange.ewsuserdirectory"); 088 _ewsUserDirectoryIds = _getUserDirectoryIds(userDirectoryIdsAsString, allowedUserDirectoryIds); 089 } 090 091 if (graph) 092 { 093 String userDirectoryIdsAsString = Config.getInstance().getValue("org.ametys.plugins.exchange.graphuserdirectory"); 094 _graphUserDirectoryIds = _getUserDirectoryIds(userDirectoryIdsAsString, allowedUserDirectoryIds); 095 } 096 097 if (graph && ews) 098 { 099 List<String> allowedExchangeUserDirectoryIds = _getAllowedUserDirectoryIds(_ewsUserDirectoryIds); 100 List<String> allowedGraphUserDirectoryIds = _getAllowedUserDirectoryIds(_graphUserDirectoryIds); 101 102 if (CollectionUtils.containsAny(allowedExchangeUserDirectoryIds, allowedGraphUserDirectoryIds)) 103 { 104 throw new IllegalStateException("The directory ids defined in Azure application and Exchange Server share same user directory"); 105 } 106 } 107 } 108 109 private List<String> _getUserDirectoryIds(String userDirectoryIdsAsString, List<String> allowedUserDirectoryIds) 110 { 111 List<String> ids = new ArrayList<>(); 112 113 if (StringUtils.isNotBlank(userDirectoryIdsAsString)) 114 { 115 String[] userDirectoryIds = StringUtils.split(userDirectoryIdsAsString, ","); 116 117 List<String> wrongUserDirectoryIds = new ArrayList<>(); 118 for (String userDirectoryId : userDirectoryIds) 119 { 120 String userDirectoryIdTrimed = StringUtils.trim(userDirectoryId); 121 if (!allowedUserDirectoryIds.contains(userDirectoryIdTrimed)) 122 { 123 wrongUserDirectoryIds.add(userDirectoryIdTrimed); 124 } 125 else 126 { 127 ids.add(userDirectoryIdTrimed); 128 } 129 } 130 131 if (!wrongUserDirectoryIds.isEmpty()) 132 { 133 throw new IllegalStateException("The following user directory ids defined in the Exchange configuration do not exist : " + wrongUserDirectoryIds); 134 } 135 } 136 137 return ids; 138 } 139 140 private List<String> _getAllowedUserDirectoryIds(List<String> userDirectoryIds) 141 { 142 if (userDirectoryIds.isEmpty()) 143 { 144 List<String> allowedUserDirectoryIds = getAllowedPopulationIds() 145 .stream() 146 .map(populationId -> _userPopulationDAO.getUserPopulation(populationId)) 147 .map(UserPopulation::getUserDirectories) 148 .flatMap(List::stream) 149 .map(UserDirectory::getId) 150 .collect(Collectors.toList()); 151 return allowedUserDirectoryIds; 152 } 153 else 154 { 155 return userDirectoryIds; 156 } 157 } 158 159 private ConnectorType _getConnectorTypeByUserIdentity(UserIdentity userIdentity) 160 { 161 User user = _userManager.getUser(userIdentity); 162 UserDirectory userDirectory = user.getUserDirectory(); 163 String userDirectoryId = userDirectory.getId(); 164 return _getConnectorTypeByUserDirectory(userDirectoryId); 165 } 166 167 private ConnectorType _getConnectorTypeByUserDirectory(String userDirectoryId) 168 { 169 Boolean exchange = Config.getInstance().getValue("org.ametys.plugins.exchange.ews"); 170 Boolean graph = Config.getInstance().getValue("org.ametys.plugins.exchange.graph"); 171 172 if (!exchange && !graph) 173 { 174 return ConnectorType.NO_CONNECTOR_CONFIGURED; 175 } 176 else if (exchange && !graph) 177 { 178 return ConnectorType.EXCHANGE_CONNECTOR; 179 } 180 else if (!exchange && graph) 181 { 182 return ConnectorType.GRAPH_CONNECTOR; 183 } 184 else if (exchange && graph) 185 { 186 boolean idIsInExchangeList = _getAllowedUserDirectoryIds(_ewsUserDirectoryIds).contains(userDirectoryId); 187 boolean idIsInGraphList = _getAllowedUserDirectoryIds(_graphUserDirectoryIds).contains(userDirectoryId); 188 189 if (idIsInExchangeList && !idIsInGraphList) 190 { 191 return ConnectorType.EXCHANGE_CONNECTOR; 192 } 193 else if (!idIsInExchangeList && idIsInGraphList) 194 { 195 return ConnectorType.GRAPH_CONNECTOR; 196 } 197 } 198 199 return ConnectorType.NO_CONNECTOR_ASSIGNED; 200 } 201 202 /** 203 * Rights profiles 204 */ 205 private enum ConnectorType 206 { 207 /** Graph connector */ 208 GRAPH_CONNECTOR, 209 /** Exchange connector */ 210 EXCHANGE_CONNECTOR, 211 /** No connector configured */ 212 NO_CONNECTOR_CONFIGURED, 213 /** No connector assigned */ 214 NO_CONNECTOR_ASSIGNED; 215 216 @Override 217 public String toString() 218 { 219 return name().toLowerCase(); 220 } 221 } 222 223 @Override 224 protected List<CalendarEvent> internalGetEvents(UserIdentity userIdentity, int maxDays, int maxEvents) throws MessagingConnectorException 225 { 226 switch (_getConnectorTypeByUserIdentity(userIdentity)) 227 { 228 case GRAPH_CONNECTOR: 229 return _graphConnector.internalGetEvents(userIdentity, maxDays, maxEvents); 230 case EXCHANGE_CONNECTOR: 231 return _ewsConnector.internalGetEvents(userIdentity, maxDays, maxEvents); 232 default: 233 throw new MessagingConnectorException("Cannot get events for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 234 } 235 } 236 237 @Override 238 protected int internalGetEventsCount(UserIdentity userIdentity, int maxDays) throws MessagingConnectorException 239 { 240 switch (_getConnectorTypeByUserIdentity(userIdentity)) 241 { 242 case GRAPH_CONNECTOR: 243 return _graphConnector.internalGetEventsCount(userIdentity, maxDays); 244 case EXCHANGE_CONNECTOR: 245 return _ewsConnector.internalGetEventsCount(userIdentity, maxDays); 246 default: 247 throw new MessagingConnectorException("Cannot get events count for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 248 } 249 } 250 251 @Override 252 protected List<EmailMessage> internalGetEmails(UserIdentity userIdentity, int maxEmails) throws MessagingConnectorException 253 { 254 switch (_getConnectorTypeByUserIdentity(userIdentity)) 255 { 256 case GRAPH_CONNECTOR: 257 return _graphConnector.internalGetEmails(userIdentity, maxEmails); 258 case EXCHANGE_CONNECTOR: 259 return _ewsConnector.internalGetEmails(userIdentity, maxEmails); 260 default: 261 throw new MessagingConnectorException("Cannot get emails for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 262 } 263 } 264 265 @Override 266 protected int internalGetEmailsCount(UserIdentity userIdentity) throws MessagingConnectorException 267 { 268 switch (_getConnectorTypeByUserIdentity(userIdentity)) 269 { 270 case GRAPH_CONNECTOR: 271 return _graphConnector.internalGetEmailsCount(userIdentity); 272 case EXCHANGE_CONNECTOR: 273 return _ewsConnector.internalGetEmailsCount(userIdentity); 274 default: 275 throw new MessagingConnectorException("Cannot get emails count for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 276 } 277 } 278 279 @Override 280 public boolean supportUserCredential(UserIdentity userIdentity) 281 { 282 switch (_getConnectorTypeByUserIdentity(userIdentity)) 283 { 284 case GRAPH_CONNECTOR: 285 return _graphConnector.supportUserCredential(userIdentity); 286 case EXCHANGE_CONNECTOR: 287 return _ewsConnector.supportUserCredential(userIdentity); 288 default: 289 throw new MessagingConnectorException("Cannot get support for credential for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 290 } 291 } 292}