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.plugins.zimbra; 017 018import java.io.UnsupportedEncodingException; 019import java.nio.charset.StandardCharsets; 020import java.security.InvalidKeyException; 021import java.security.NoSuchAlgorithmException; 022import java.util.ArrayList; 023import java.util.List; 024 025import javax.crypto.Mac; 026import javax.crypto.spec.SecretKeySpec; 027 028import org.apache.commons.codec.binary.Hex; 029import org.apache.commons.lang3.StringUtils; 030import org.apache.http.NameValuePair; 031import org.apache.http.client.methods.CloseableHttpResponse; 032import org.apache.http.client.methods.HttpGet; 033import org.apache.http.client.protocol.HttpClientContext; 034import org.apache.http.client.utils.URLEncodedUtils; 035import org.apache.http.cookie.Cookie; 036import org.apache.http.impl.client.CloseableHttpClient; 037import org.apache.http.impl.client.HttpClients; 038import org.apache.http.message.BasicNameValuePair; 039 040import org.ametys.runtime.model.checker.ItemChecker; 041import org.ametys.runtime.model.checker.ItemCheckerTestFailureException; 042 043/** 044 * Item Checker testing the connection to a zimbra server using a test user 045 */ 046public class ZimbraConnectionChecker implements ItemChecker 047{ 048 public void check(List<String> values) throws ItemCheckerTestFailureException 049 { 050 String url = values.get(0); 051 String preAuthToken = values.get(1); 052 String testUser = values.get(2); 053 054 try (CloseableHttpClient httpClient = HttpClients.createDefault()) 055 { 056 String qs = _computeQueryString(testUser, preAuthToken); 057 058 HttpGet get = new HttpGet(url + "/service/preauth?" + qs); 059 HttpClientContext context = HttpClientContext.create(); 060 try (CloseableHttpResponse response = httpClient.execute(get, context)) 061 { 062 List<Cookie> cookies = context.getCookieStore().getCookies(); 063 064 for (Cookie cookie : cookies) 065 { 066 if (StringUtils.equals(cookie.getName(), "ZM_AUTH_TOKEN")) 067 { 068 return; 069 } 070 } 071 072 throw new ItemCheckerTestFailureException("Failed to authenticate the test user. Server response: '" + response.getStatusLine().toString() + "'"); 073 } 074 } 075 catch (Exception e) 076 { 077 throw new ItemCheckerTestFailureException(e); 078 } 079 } 080 081 private String _computeQueryString(String zimbraUser, String secretKey) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException 082 { 083 String timestamp = String.valueOf(System.currentTimeMillis()); 084 String computedPreauth = _getComputedPreauth(zimbraUser, timestamp, secretKey); 085 086 // Preauth request parameters 087 List<NameValuePair> params = new ArrayList<>(); 088 params.add(new BasicNameValuePair("account", zimbraUser)); 089 params.add(new BasicNameValuePair("timestamp", timestamp)); 090 params.add(new BasicNameValuePair("expires", "0")); 091 params.add(new BasicNameValuePair("preauth", computedPreauth)); 092 093 // Computing query string 094 return URLEncodedUtils.format(params, StandardCharsets.UTF_8); 095 } 096 097 private String _getComputedPreauth(String zimbraUser, String timestamp, String secretKey) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException 098 { 099 SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); 100 Mac mac = Mac.getInstance("HmacSHA1"); 101 mac.init(signingKey); 102 103 String data = StringUtils.join(new String[] {zimbraUser, "name", "0", timestamp}, '|'); 104 byte[] rawHmac = mac.doFinal(data.getBytes()); 105 byte[] hexBytes = new Hex().encode(rawHmac); 106 return new String(hexBytes, "UTF-8"); 107 } 108}