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.captchetat.captcha; 017 018import java.io.IOException; 019import java.io.OutputStream; 020import java.nio.charset.StandardCharsets; 021import java.util.Map; 022 023import org.apache.avalon.framework.activity.Disposable; 024import org.apache.avalon.framework.activity.Initializable; 025import org.apache.avalon.framework.logger.AbstractLogEnabled; 026import org.apache.avalon.framework.parameters.Parameters; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.cocoon.ProcessingException; 031import org.apache.cocoon.environment.ObjectModelHelper; 032import org.apache.cocoon.environment.Request; 033import org.apache.cocoon.environment.SourceResolver; 034import org.apache.cocoon.reading.Reader; 035import org.apache.commons.lang3.StringUtils; 036import org.apache.hc.client5.http.classic.methods.HttpGet; 037import org.apache.hc.client5.http.config.RequestConfig; 038import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; 039import org.apache.hc.core5.http.ClassicHttpResponse; 040import org.apache.hc.core5.http.HttpEntity; 041import org.apache.hc.core5.http.ParseException; 042import org.apache.hc.core5.http.io.entity.EntityUtils; 043import org.apache.hc.core5.io.CloseMode; 044import org.xml.sax.SAXException; 045 046import org.ametys.core.util.HttpUtils; 047 048/** 049 * Reader implementation that add header for Captchetat requests 050 */ 051public class CaptchetatReader extends AbstractLogEnabled implements Reader, Serviceable, Initializable, Disposable 052{ 053 /** The CaptchEtat helper */ 054 protected CaptchEtatHelper _captchEtatHelper; 055 056 private OutputStream _os; 057 058 private CloseableHttpClient _httpClient; 059 private ClassicHttpResponse _response; 060 061 062 public void service(ServiceManager manager) throws ServiceException 063 { 064 _captchEtatHelper = (CaptchEtatHelper) manager.lookup(CaptchEtatHelper.ROLE); 065 } 066 067 public void initialize() throws Exception 068 { 069 _httpClient = HttpUtils.createHttpClient(0, 20, false); 070 } 071 072 public void dispose() 073 { 074 _httpClient.close(CloseMode.GRACEFUL); 075 } 076 077 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException 078 { 079 080 Request request = ObjectModelHelper.getRequest(objectModel); 081 082 String url = _captchEtatHelper.getEndpoint() + "simple-captcha-endpoint?" + StringUtils.defaultString(request.getQueryString()); 083 084 HttpGet httpGet = new HttpGet(url); 085 RequestConfig config = RequestConfig.custom() 086 .setRedirectsEnabled(false) 087 .build(); 088 httpGet.setConfig(config); 089 090 String token = _captchEtatHelper.getToken(); 091 httpGet.addHeader("Authorization", "Bearer " + token); 092 093 _response = _httpClient.executeOpen(null, httpGet, null); 094 switch (_response.getCode()) 095 { 096 case 200: 097 break; 098 099 case 403: 100 _response.close(); 101 throw new IllegalStateException("CaptchEtat refused the connection"); 102 103 case 500: 104 default: 105 try 106 { 107 throw new IllegalStateException("CaptchEtat returned an error: " + EntityUtils.toString(_response.getEntity(), StandardCharsets.UTF_8)); 108 } 109 catch (ParseException e) 110 { 111 throw new IllegalStateException("CaptchEtat returned an error"); 112 } 113 finally 114 { 115 _response.close(); 116 } 117 } 118 } 119 120 public void setOutputStream(OutputStream out) throws IOException 121 { 122 _os = out; 123 } 124 125 public String getMimeType() 126 { 127 HttpEntity entity = _response.getEntity(); 128 return entity != null ? entity.getContentType() : null; 129 } 130 131 public boolean shouldSetContentLength() 132 { 133 return false; 134 } 135 136 public void generate() throws IOException, SAXException, ProcessingException 137 { 138 try 139 { 140 _response.getEntity().writeTo(_os); 141 } 142 finally 143 { 144 _response.close(); 145 } 146 } 147 148 public long getLastModified() 149 { 150 return 0; 151 } 152}