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 _ewsUserDirectoryIds = new ArrayList<>(); 067 _graphUserDirectoryIds = new ArrayList<>(); 068 069 Boolean ews = Config.getInstance().getValue("org.ametys.plugins.exchange.ews"); 070 Boolean graph = Config.getInstance().getValue("org.ametys.plugins.exchange.graph"); 071 072 List<String> allowedUserDirectoryIds = getAllowedPopulationIds() 073 .stream() 074 .map(populationId -> _userPopulationDAO.getUserPopulation(populationId)) 075 .map(UserPopulation::getUserDirectories) 076 .flatMap(List::stream) 077 .map(UserDirectory::getId) 078 .collect(Collectors.toList()); 079 080 if (ews) 081 { 082 String userDirectoryIdsAsString = Config.getInstance().getValue("org.ametys.plugins.exchange.ewsuserdirectory"); 083 _ewsUserDirectoryIds = _getUserDirectoryIds(userDirectoryIdsAsString, allowedUserDirectoryIds); 084 } 085 086 if (graph) 087 { 088 String userDirectoryIdsAsString = Config.getInstance().getValue("org.ametys.plugins.exchange.graphuserdirectory"); 089 _graphUserDirectoryIds = _getUserDirectoryIds(userDirectoryIdsAsString, allowedUserDirectoryIds); 090 } 091 092 if (graph && ews) 093 { 094 List<String> allowedExchangeUserDirectoryIds = _getAllowedUserDirectoryIds(_ewsUserDirectoryIds); 095 List<String> allowedGraphUserDirectoryIds = _getAllowedUserDirectoryIds(_graphUserDirectoryIds); 096 097 if (CollectionUtils.containsAny(allowedExchangeUserDirectoryIds, allowedGraphUserDirectoryIds)) 098 { 099 throw new IllegalStateException("The directory ids defined in Azure application and Exchange Server share same user directory"); 100 } 101 } 102 } 103 104 private List<String> _getUserDirectoryIds(String userDirectoryIdsAsString, List<String> allowedUserDirectoryIds) 105 { 106 List<String> ids = new ArrayList<>(); 107 108 if (StringUtils.isNotBlank(userDirectoryIdsAsString)) 109 { 110 String[] userDirectoryIds = StringUtils.split(userDirectoryIdsAsString, ","); 111 112 List<String> wrongUserDirectoryIds = new ArrayList<>(); 113 for (String userDirectoryId : userDirectoryIds) 114 { 115 String userDirectoryIdTrimed = StringUtils.trim(userDirectoryId); 116 if (!allowedUserDirectoryIds.contains(userDirectoryIdTrimed)) 117 { 118 wrongUserDirectoryIds.add(userDirectoryIdTrimed); 119 } 120 else 121 { 122 ids.add(userDirectoryIdTrimed); 123 } 124 } 125 126 if (!wrongUserDirectoryIds.isEmpty()) 127 { 128 throw new IllegalStateException("The following user directory ids defined in the Exchange configuration do not exist : " + wrongUserDirectoryIds); 129 } 130 } 131 132 return ids; 133 } 134 135 private List<String> _getAllowedUserDirectoryIds(List<String> userDirectoryIds) 136 { 137 if (userDirectoryIds.isEmpty()) 138 { 139 List<String> allowedUserDirectoryIds = getAllowedPopulationIds() 140 .stream() 141 .map(populationId -> _userPopulationDAO.getUserPopulation(populationId)) 142 .map(UserPopulation::getUserDirectories) 143 .flatMap(List::stream) 144 .map(UserDirectory::getId) 145 .collect(Collectors.toList()); 146 return allowedUserDirectoryIds; 147 } 148 else 149 { 150 return userDirectoryIds; 151 } 152 } 153 154 private ConnectorType _getConnectorTypeByUserIdentity(UserIdentity userIdentity) 155 { 156 User user = _userManager.getUser(userIdentity); 157 UserDirectory userDirectory = user.getUserDirectory(); 158 String userDirectoryId = userDirectory.getId(); 159 return _getConnectorTypeByUserDirectory(userDirectoryId); 160 } 161 162 private ConnectorType _getConnectorTypeByUserDirectory(String userDirectoryId) 163 { 164 Boolean exchange = Config.getInstance().getValue("org.ametys.plugins.exchange.ews"); 165 Boolean graph = Config.getInstance().getValue("org.ametys.plugins.exchange.graph"); 166 167 if (!exchange && !graph) 168 { 169 return null; 170 } 171 else if (exchange && !graph) 172 { 173 return ConnectorType.EXCHANGE_CONNECTOR; 174 } 175 else if (!exchange && graph) 176 { 177 return ConnectorType.GRAPH_CONNECTOR; 178 } 179 else if (exchange && graph) 180 { 181 boolean idIsInExchangeList = _getAllowedUserDirectoryIds(_ewsUserDirectoryIds).contains(userDirectoryId); 182 boolean idIsInGraphList = _getAllowedUserDirectoryIds(_graphUserDirectoryIds).contains(userDirectoryId); 183 184 if (idIsInExchangeList && !idIsInGraphList) 185 { 186 return ConnectorType.EXCHANGE_CONNECTOR; 187 } 188 else if (!idIsInExchangeList && idIsInGraphList) 189 { 190 return ConnectorType.GRAPH_CONNECTOR; 191 } 192 } 193 194 return null; 195 } 196 197 /** 198 * Rights profiles 199 */ 200 private enum ConnectorType 201 { 202 /** Graph connector */ 203 GRAPH_CONNECTOR, 204 /** Exchange connector */ 205 EXCHANGE_CONNECTOR; 206 207 @Override 208 public String toString() 209 { 210 return name().toLowerCase(); 211 } 212 } 213 214 @Override 215 protected List<CalendarEvent> internalGetEvents(UserIdentity userIdentity, int maxDays, int maxEvents) throws MessagingConnectorException 216 { 217 switch (_getConnectorTypeByUserIdentity(userIdentity)) 218 { 219 case GRAPH_CONNECTOR: 220 return _graphConnector.internalGetEvents(userIdentity, maxDays, maxEvents); 221 case EXCHANGE_CONNECTOR: 222 return _ewsConnector.internalGetEvents(userIdentity, maxDays, maxEvents); 223 default: 224 throw new MessagingConnectorException("Cannot get events for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 225 } 226 } 227 228 @Override 229 protected int internalGetEventsCount(UserIdentity userIdentity, int maxDays) throws MessagingConnectorException 230 { 231 switch (_getConnectorTypeByUserIdentity(userIdentity)) 232 { 233 case GRAPH_CONNECTOR: 234 return _graphConnector.internalGetEventsCount(userIdentity, maxDays); 235 case EXCHANGE_CONNECTOR: 236 return _ewsConnector.internalGetEventsCount(userIdentity, maxDays); 237 default: 238 throw new MessagingConnectorException("Cannot get events count for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 239 } 240 } 241 242 @Override 243 protected List<EmailMessage> internalGetEmails(UserIdentity userIdentity, int maxEmails) throws MessagingConnectorException 244 { 245 switch (_getConnectorTypeByUserIdentity(userIdentity)) 246 { 247 case GRAPH_CONNECTOR: 248 return _graphConnector.internalGetEmails(userIdentity, maxEmails); 249 case EXCHANGE_CONNECTOR: 250 return _ewsConnector.internalGetEmails(userIdentity, maxEmails); 251 default: 252 throw new MessagingConnectorException("Cannot get emails for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 253 } 254 } 255 256 @Override 257 protected int internalGetEmailsCount(UserIdentity userIdentity) throws MessagingConnectorException 258 { 259 switch (_getConnectorTypeByUserIdentity(userIdentity)) 260 { 261 case GRAPH_CONNECTOR: 262 return _graphConnector.internalGetEmailsCount(userIdentity); 263 case EXCHANGE_CONNECTOR: 264 return _ewsConnector.internalGetEmailsCount(userIdentity); 265 default: 266 throw new MessagingConnectorException("Cannot get emails count for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 267 } 268 } 269 270 @Override 271 public boolean supportUserCredential(UserIdentity userIdentity) 272 { 273 switch (_getConnectorTypeByUserIdentity(userIdentity)) 274 { 275 case GRAPH_CONNECTOR: 276 return _graphConnector.supportUserCredential(userIdentity); 277 case EXCHANGE_CONNECTOR: 278 return _ewsConnector.supportUserCredential(userIdentity); 279 default: 280 throw new MessagingConnectorException("Cannot get support for credential for user " + userIdentity + ": user directory is not supported by this messaging connector", MessagingConnectorException.ExceptionType.CONFIGURATION_EXCEPTION); 281 } 282 } 283}