/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.submit.filters; import com.eviware.soapui.config.CredentialsConfig; import com.eviware.soapui.impl.rest.OAuth2Profile; import com.eviware.soapui.impl.rest.OAuth2ProfileContainer; import com.eviware.soapui.impl.rest.RestRequest; import com.eviware.soapui.impl.rest.actions.oauth.OAuth2ClientFacade; import com.eviware.soapui.impl.rest.actions.oauth.OAuth2TestUtils; import com.eviware.soapui.impl.wsdl.WsdlProject; import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod; import com.eviware.soapui.model.iface.SubmitContext; import com.eviware.soapui.support.SoapUIException; import com.eviware.soapui.utils.ModelItemFactory; import org.apache.log4j.Logger; import org.apache.oltu.oauth2.common.OAuth; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.List; import static com.eviware.soapui.config.CredentialsConfig.AuthType.O_AUTH_2_0; import static com.eviware.soapui.config.CredentialsConfig.AuthType.PREEMPTIVE; import static com.eviware.soapui.utils.CommonMatchers.anEmptyArray; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class OAuth2RequestFilterTest { public static final String EXPIRED_TOKEN = "EXPIRED#TOKEN"; private static final String ACCESS_TOKEN = "ACDFECDSFKJFK#SDFSD8df#ACCESS-TOKEN"; private static final String RETRIEVED_ACCESS_TOKEN = "yyCDFECDSFKJFK#dsfsddf#28317"; private OAuth2RequestFilter oAuth2RequestFilter; private RestRequest restRequest; private ExtendedPostMethod httpRequest; private OAuth2ProfileContainer oAuth2ProfileContainer; @Mock private SubmitContext mockContext; @Mock private Logger mockLogger; private Logger realLogger; private OAuth2Profile oAuth2Profile; @Before public void setUp() throws SoapUIException, URISyntaxException { MockitoAnnotations.initMocks(this); oAuth2RequestFilter = new OAuth2RequestFilter(); setupModelItems(); setupRequest(); replaceLogger(); } @After public void restoreLogger() throws Exception { OAuth2RequestFilter.setLog(realLogger); } /* Tests */ @Test public void appliesAccessToken() throws URISyntaxException { String expectedAccessTokenValue = "Bearer " + ACCESS_TOKEN; oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); assertThat(httpRequest.getHeaders(OAuth.HeaderType.AUTHORIZATION)[0].getValue(), is(expectedAccessTokenValue)); } @Test public void doesNotApplyNullAccessTokenToHeader() throws Exception { oAuth2Profile.setAccessToken(null); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); assertThat(httpRequest.getHeaders(OAuth.HeaderType.AUTHORIZATION), is(anEmptyArray())); } @Test public void doesNotApplyAccessTokenIfOAuthTypeIsNotOAuth2() { restRequest.setSelectedAuthProfileAndAuthType(PREEMPTIVE.toString(), PREEMPTIVE); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); assertThat(httpRequest.getHeaders(OAuth.HeaderType.AUTHORIZATION), is(anEmptyArray())); } @Test public void automaticallyRefreshAccessTokenIfExpired() throws Exception { OAuth2Profile profileWithRefreshToken = setProfileWithRefreshTokenAndExpiredAccessToken(); oAuth2FilterWithMockOAuth2ClientFacade(profileWithRefreshToken); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); String actualAccessTokenHeader = httpRequest.getHeaders((OAuth.HeaderType.AUTHORIZATION))[0].getValue(); assertThat(actualAccessTokenHeader, is("Bearer " + OAuth2TestUtils.ACCESS_TOKEN)); } @Test public void automaticallyRefreshesAccessTokenIfExpired() throws Exception { setupProfileWithRefreshToken(); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); String actualAccessTokenHeader = httpRequest.getHeaders((OAuth.HeaderType.AUTHORIZATION))[0].getValue(); assertThat(actualAccessTokenHeader, is("Bearer " + OAuth2TestUtils.ACCESS_TOKEN)); } @Test public void doesNotRefreshAccessTokenWhenRefreshMethodIsManual() throws SoapUIException { OAuth2Profile profileWithRefreshToken = setProfileWithRefreshTokenAndExpiredAccessToken(); profileWithRefreshToken.setRefreshAccessTokenMethod(OAuth2Profile.RefreshAccessTokenMethods.MANUAL); oAuth2FilterWithMockOAuth2ClientFacade(profileWithRefreshToken); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); assertThat(profileWithRefreshToken.getAccessToken(), is(EXPIRED_TOKEN)); } private OAuth2Profile setProfileWithRefreshTokenAndExpiredAccessToken() throws SoapUIException { final OAuth2Profile profileWithRefreshToken = OAuth2TestUtils.getOAuthProfileWithRefreshToken(); setExpiredAccessToken(profileWithRefreshToken); oAuth2ProfileContainer.getOAuth2ProfileList().set(0, profileWithRefreshToken); restRequest.setSelectedAuthProfileAndAuthType(profileWithRefreshToken.getName(), O_AUTH_2_0); return profileWithRefreshToken; } @Test public void automaticallyReloadsAccessTokenWhenProfileHasAutomationScripts() throws Exception { setupProfileWithAutomationScripts(); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); String actualAccessTokenHeader = httpRequest.getHeaders((OAuth.HeaderType.AUTHORIZATION))[0].getValue(); assertThat(actualAccessTokenHeader, is("Bearer " + RETRIEVED_ACCESS_TOKEN)); } @Test public void addsLogStatementsWhenRefreshingAccessToken() throws Exception { setupProfileWithRefreshToken(); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); verify(mockLogger, times(2)).info(any(String.class)); } @Test public void addsLogStatementsWhenReloadingAccessToken() throws Exception { setupProfileWithAutomationScripts(); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); verify(mockLogger, times(2)).info(any(String.class)); } @Test public void refreshAccessTokenIfManualExpirationTimeIsSetAndManualExpirationTimeHasPassed() throws Exception { setupProfileWithRefreshToken(); oAuth2Profile.setAccessTokenExpirationTime(3600); oAuth2Profile.setManualAccessTokenExpirationTime("1"); oAuth2Profile.setUseManualAccessTokenExpirationTime(true); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); String actualAccessTokenHeader = httpRequest.getHeaders((OAuth.HeaderType.AUTHORIZATION))[0].getValue(); assertThat(actualAccessTokenHeader, is("Bearer " + OAuth2TestUtils.ACCESS_TOKEN)); } @Test public void doesNotRefreshAccessTokenEvenIfExpiredWhenManualExpirationTimeIsSelected() throws Exception { setupProfileWithRefreshToken(); oAuth2Profile.setAccessTokenIssuedTime(System.currentTimeMillis()); oAuth2Profile.setAccessTokenExpirationTime(1); //We use a 10 second buffer when checking for expiration, so this will count as expired. oAuth2Profile.setUseManualAccessTokenExpirationTime(true); oAuth2Profile.setManualAccessTokenExpirationTime("3600"); String originalAccessToken = oAuth2Profile.getAccessToken(); oAuth2RequestFilter.filterRestRequest(mockContext, restRequest); assertThat(oAuth2Profile.getAccessToken(), is(originalAccessToken)); } /* Setup helpers. */ private void setupRequest() throws URISyntaxException { httpRequest = new ExtendedPostMethod(); httpRequest.setURI(new URI("endpoint/path")); when(mockContext.getProperty(BaseHttpRequestTransport.HTTP_METHOD)).thenReturn(httpRequest); } private void setupModelItems() throws SoapUIException { restRequest = ModelItemFactory.makeRestRequest(); WsdlProject project = restRequest.getOperation().getInterface().getProject(); oAuth2ProfileContainer = project.getOAuth2ProfileContainer(); List<OAuth2Profile> oAuth2ProfileList = oAuth2ProfileContainer.getOAuth2ProfileList(); if (oAuth2ProfileList.isEmpty()) { oAuth2Profile = oAuth2ProfileContainer.addNewOAuth2Profile("OAuth 2 - Profile"); } else { oAuth2Profile = oAuth2ProfileList.get(0); } restRequest.setSelectedAuthProfileAndAuthType(oAuth2Profile.getName(), O_AUTH_2_0); oAuth2Profile.setAccessToken(ACCESS_TOKEN); } private void replaceLogger() { realLogger = OAuth2RequestFilter.getLog(); OAuth2RequestFilter.setLog(mockLogger); } private void setupProfileWithRefreshToken() throws SoapUIException { final OAuth2Profile profileWithRefreshToken = OAuth2TestUtils.getOAuthProfileWithRefreshToken(); setExpiredAccessToken(profileWithRefreshToken); injectProfile(profileWithRefreshToken); oAuth2ProfileContainer.getOAuth2ProfileList().set(0, profileWithRefreshToken); oAuth2Profile = profileWithRefreshToken; oAuth2FilterWithMockOAuth2ClientFacade(oAuth2Profile); } private void oAuth2FilterWithMockOAuth2ClientFacade(final OAuth2Profile profileWithRefreshToken) { oAuth2RequestFilter = new OAuth2RequestFilter() { @Override protected OAuth2ClientFacade getOAuth2ClientFacade() { return OAuth2TestUtils.getOltuOAuth2ClientFacadeWithMockedTokenExtractor(profileWithRefreshToken); } }; } private void setupProfileWithAutomationScripts() throws SoapUIException { final OAuth2Profile profileWithAutomationScripts = makeProfileWithAutomationScripts(); setExpiredAccessToken(profileWithAutomationScripts); injectProfile(profileWithAutomationScripts); oAuth2FilterWithMockOAuth2ClientFacade(profileWithAutomationScripts); Runnable browserCallbackSimulator = new Runnable() { public void run() { try { Thread.sleep(50); } catch (InterruptedException ignore) { } profileWithAutomationScripts.applyRetrievedAccessToken(RETRIEVED_ACCESS_TOKEN); } }; new Thread(browserCallbackSimulator).start(); } private void injectProfile(final OAuth2Profile profileWithAutomationScripts) { oAuth2ProfileContainer.getOAuth2ProfileList().set(0, profileWithAutomationScripts); restRequest.setSelectedAuthProfileAndAuthType(profileWithAutomationScripts.getName(), CredentialsConfig.AuthType.O_AUTH_2_0); oAuth2Profile = profileWithAutomationScripts; } private OAuth2Profile makeProfileWithAutomationScripts() throws SoapUIException { final OAuth2Profile profileWithAutomationScripts = OAuth2TestUtils.getOAuthProfileWithDefaultValues(); profileWithAutomationScripts.setAutomationJavaScripts(Arrays.asList("doLoginAndConsent()")); return profileWithAutomationScripts; } private void setExpiredAccessToken(OAuth2Profile profileWithRefreshToken) { profileWithRefreshToken.setAccessToken(EXPIRED_TOKEN); profileWithRefreshToken.setAccessTokenIssuedTime(1); //Token was issued Jan 1 1970 profileWithRefreshToken.setAccessTokenExpirationTime(10); //and expired 10 seconds later. } }