diff --git a/docs/index.adoc b/docs/index.adoc index 07cfe1af..77cffc70 100644 --- a/docs/index.adoc +++ b/docs/index.adoc @@ -115,7 +115,10 @@ include::manual/testdefinition/advanced-topics/sahi-settings-browser-selection.a include::manual/testdefinition/advanced-topics/sahi-settings-browser-config.adoc[] include::manual/testdefinition/advanced-topics/sahi-settings-proxy.adoc[] include::manual/testdefinition/advanced-topics/sahi-https.adoc[] + +==== Sahi known issues include::manual/testdefinition/advanced-topics/sahi-webpack.adoc[] +include::manual/testdefinition/advanced-topics/sahi-authorization-header.adoc[] ==== Sikuli settings include::manual/testdefinition/advanced-topics/sikuli-settings-highlighting.adoc[] diff --git a/docs/manual/testdefinition/advanced-topics/sahi-authorization-header.adoc b/docs/manual/testdefinition/advanced-topics/sahi-authorization-header.adoc new file mode 100644 index 00000000..6be391fe --- /dev/null +++ b/docs/manual/testdefinition/advanced-topics/sahi-authorization-header.adoc @@ -0,0 +1,20 @@ + +:imagesdir: ../../../images + +[[sahi-authorization-headers]] +===== Sahi removes authorization headers +[#git-edit-section] +:page-path: docs/manual/testdefinition/advanced-topics/sahi-authorization-header.adoc +git-link:{page-path}{git-view} | git-link:{page-path}{git-edit} + +Due to issue https://github.com/ConSol/sakuli/issues/306[Disable Sahi proxy method which remove the authorization header (e.g. Bearer Token) #306] Sahi OS have currently some problems with handling authorization tokens like Bearer Token correctly. This has been also discussed at https://community.sahipro.com/forums/discussion/3941/authorization-header-getting-stripped-out[Sahi Community - Authorization header getting stripped out] and is a Problem of Sahi OS. + +This behavior is not wanted, so the Sakuli team developed a solution which manipulates Sahi by some https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/aop.html[Spring AOP Advice], for some details take look at https://github.com/ConSol/sakuli/blob/feature/%23306-sahi-header/src/core/src/main/java/org/sakuli/aop/SahiHeaderAspect.java#L59[Sahi Header Aspect] + +By default nothing have been changed to avoid unexpected impact to other parts of Sahi OS. To skip the execution of the Sahi action which removes the authorization header , see https://github.com/kevlened/Sahi/blob/744f77462badeb3deddce93ddf6374773f70833f/sahi/src/net/sf/sahi/request/HttpRequest.java#L272[`HttpRequest.removeHeader("Authorization")`], set the following <> to `false`: + + sahi.proxy.removeAuthorizationHeader.enabled=false + + +For more details see issue https://github.com/ConSol/sakuli/issues/306[#306]. + diff --git a/src/common/src/main/resources/org/sakuli/common/config/sakuli-default.properties b/src/common/src/main/resources/org/sakuli/common/config/sakuli-default.properties index d2a3d3ba..1e0981d6 100644 --- a/src/common/src/main/resources/org/sakuli/common/config/sakuli-default.properties +++ b/src/common/src/main/resources/org/sakuli/common/config/sakuli-default.properties @@ -375,8 +375,8 @@ sahi.proxy.maxConnectTries=25 sahi.proxy.reconnectSeconds=1 # amount of firefox profiles ff.profiles.max_number=1 - - +#### Sahi customisations done by Sakuli only +# # Sahi delays on Sikuli input (put on helmet!) # # Sikuli keyboard events (type/paste) on a Sahi-controlled browser instance can get lost if @@ -397,6 +397,12 @@ ff.profiles.max_number=1 # (gets only enabled if delayPerKey is set) sahi.proxy.onSikuliInput.delayBeforeInput=500 sahi.proxy.onSikuliInput.delayPerKey= +# +# Dis/Enable if Sahi should remove the authorization header. +# See: http://consol.github.io/sakuli/latest/index.html#sahi-authorization-headers +# (Default by Sahi OS: true) +sahi.proxy.removeAuthorizationHeader.enabled=true + ### HTTP/HTTPS proxy Settings ### Set a company proxy Sahi should use diff --git a/src/core/src/main/java/org/sakuli/aop/SahiHeaderAspect.java b/src/core/src/main/java/org/sakuli/aop/SahiHeaderAspect.java new file mode 100644 index 00000000..855b9c0b --- /dev/null +++ b/src/core/src/main/java/org/sakuli/aop/SahiHeaderAspect.java @@ -0,0 +1,70 @@ +/* + * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. + * + * Copyright 2013 - 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sakuli.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.sakuli.datamodel.properties.SahiProxyProperties; +import org.sakuli.loader.BeanLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import static java.lang.Boolean.FALSE; + +/** + * Aspect for the External Sahi Library {@link net.sf.sahi} + * + * @author tschneck Date: 17.10.13 + */ +@Aspect +@Component +public class SahiHeaderAspect extends BaseSakuliAspect { + + private final static Logger LOGGER = LoggerFactory.getLogger(SahiHeaderAspect.class); + private static Boolean removeAuthorizationHeader; + + public static boolean getRemoveAuthorizationHeader() { + if (removeAuthorizationHeader == null) { + removeAuthorizationHeader = BeanLoader.loadBaseActionLoader().getSahiProxyProperties().getRemoveAuthorizationHeader(); + if (FALSE.equals(removeAuthorizationHeader)) + LOGGER.info("{}={}: SAHI remove Header 'Authorization' is DISABLED! ", SahiProxyProperties.REMOVE_AUTHORIZATION_HEADER, removeAuthorizationHeader); + } + return removeAuthorizationHeader; + } + + /** + * Aspect to skip the execution of the action {@link net.sf.sahi.request.HttpRequest#removeHeader(String) } functionality for the headerString "Authorization" + * + * @param joinPoint injected joinPoint of the execution + * @param headerString will called with different header values from Sahi + */ + @Around("execution(* net.sf.sahi.StreamHandler.removeHeader(..)) && args(headerString)") + public void aroundSahiRemoveHeaders(ProceedingJoinPoint joinPoint, String headerString) throws Throwable { + if (FALSE.equals(getRemoveAuthorizationHeader()) && "Authorization".equals(headerString)) { + LOGGER.debug("SAHI skip remove Header '{}'", headerString); + //skip execution of method + return; + } + joinPoint.proceed(); + } + + +} diff --git a/src/core/src/main/java/org/sakuli/datamodel/properties/SahiProxyProperties.java b/src/core/src/main/java/org/sakuli/datamodel/properties/SahiProxyProperties.java index dff2bcc9..c2795300 100644 --- a/src/core/src/main/java/org/sakuli/datamodel/properties/SahiProxyProperties.java +++ b/src/core/src/main/java/org/sakuli/datamodel/properties/SahiProxyProperties.java @@ -51,6 +51,7 @@ public class SahiProxyProperties extends AbstractProperties { public static final String RECONNECT_SECONDS = "sahi.proxy.reconnectSeconds"; public static final String REQUEST_DELAY_MS = "sahi.proxy.onSikuliInput.delayPerKey"; public static final String REQUEST_DELAY_REFRESH_MS = "sahi.proxy.onSikuliInput.delayBeforeInput"; + public static final String REMOVE_AUTHORIZATION_HEADER = "sahi.proxy.removeAuthorizationHeader.enabled"; public static final String DEFAULT_PROXY_PORT = "9999"; public static final String DEFAULT_RECONNECT_SECONDS = "1"; public static final String DEFAULT_MAX_CONNECT_TRIES = "25"; @@ -124,6 +125,11 @@ public class SahiProxyProperties extends AbstractProperties { private Integer requestDelayMs; @Value("${" + REQUEST_DELAY_REFRESH_MS + ":500}") private Integer requestDelayRefreshMs; + /** + * Default behaviour of Sahi OS + */ + @Value("${" + REMOVE_AUTHORIZATION_HEADER + ":true}") + private Boolean removeAuthorizationHeader; @Autowired private SakuliProperties sakuliProperties; @Autowired @@ -256,4 +262,12 @@ public Integer getRequestDelayRefreshMs() { public void setRequestDelayRefreshMs(Integer requestDelayRefreshMs) { this.requestDelayRefreshMs = requestDelayRefreshMs; } + + public Boolean getRemoveAuthorizationHeader() { + return removeAuthorizationHeader; + } + + public void setRemoveAuthorizationHeader(Boolean removeAuthorizationHeader) { + this.removeAuthorizationHeader = removeAuthorizationHeader; + } } diff --git a/src/core/src/main/java/org/sakuli/loader/BeanLoader.java b/src/core/src/main/java/org/sakuli/loader/BeanLoader.java index f8fdd094..5f6f953a 100644 --- a/src/core/src/main/java/org/sakuli/loader/BeanLoader.java +++ b/src/core/src/main/java/org/sakuli/loader/BeanLoader.java @@ -91,7 +91,7 @@ public static Region loadRegionRectangle(int x, int y, int w, int h, String resu */ public static T loadBean(Class classDef) { try { - logger.debug("load bean '{}' from application context", classDef.getSimpleName()); + logger.trace("load bean '{}' from application context", classDef.getSimpleName()); return getBeanFactory().getBean(classDef); } catch (Throwable e) { logger.error("error in BeanLoader", e); diff --git a/src/core/src/test/java/org/sakuli/aop/SahiHeaderAspectTest.java b/src/core/src/test/java/org/sakuli/aop/SahiHeaderAspectTest.java new file mode 100644 index 00000000..6e3c2996 --- /dev/null +++ b/src/core/src/test/java/org/sakuli/aop/SahiHeaderAspectTest.java @@ -0,0 +1,72 @@ +/* + * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. + * + * Copyright 2013 - 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sakuli.aop; + +import net.sf.sahi.request.HttpRequest; +import org.sakuli.datamodel.actions.LogLevel; +import org.sakuli.loader.BeanLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * Test for {@link SahiHeaderAspect} + * + * @author tschneck + * Date: 2/25/16 + */ +public class SahiHeaderAspectTest extends AopBaseTest { + + private final static Logger LOGGER = LoggerFactory.getLogger(SahiHeaderAspect.class); + private HttpRequest testling; + + @BeforeMethod + @Override + public void setUp() throws Exception { + super.setUp(); + initMocks(); + InputStream input = new ByteArrayInputStream(new byte[]{}); + testling = new HttpRequest(input); + } + + @Test + public void testRemoveHeaderDisabeld() throws Exception { + final SahiHeaderAspect sahiHeaderAspect = BeanLoader.loadBean(SahiHeaderAspect.class); + ReflectionTestUtils.setField(sahiHeaderAspect, "removeAuthorizationHeader", false); + LOGGER.debug("SAHI this is not the correct line!"); + testling.removeHeader("Authorization"); + assertLastLine(logFile, "SAHI", LogLevel.DEBUG, "SAHI skip remove Header 'Authorization'"); + } + + @Test + public void testRemoveHeaderNotModiefied() throws Exception { + final SahiHeaderAspect sahiHeaderAspect = BeanLoader.loadBean(SahiHeaderAspect.class); + ReflectionTestUtils.setField(sahiHeaderAspect, "removeAuthorizationHeader", true); + final String controllMessage = "SAHI this is the expected line!"; + LOGGER.debug(controllMessage); + testling.removeHeader("Authorization"); + assertLastLine(logFile, "SAHI", LogLevel.DEBUG, controllMessage); + } + +} \ No newline at end of file