mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
Merged feature/qol-improvements-20240801 into dev
This commit is contained in:
@ -737,20 +737,7 @@ public class BaseAPIActionUtil
|
||||
case API_KEY_HEADER -> request.setHeader("API-Key", backendMetaData.getApiKey());
|
||||
case API_TOKEN -> request.setHeader("Authorization", "Token " + backendMetaData.getApiKey());
|
||||
case OAUTH2 -> request.setHeader("Authorization", "Bearer " + getOAuth2Token());
|
||||
case API_KEY_QUERY_PARAM ->
|
||||
{
|
||||
try
|
||||
{
|
||||
String uri = request.getURI().toString();
|
||||
uri += (uri.contains("?") ? "&" : "?");
|
||||
uri += backendMetaData.getApiKeyQueryParamName() + "=" + backendMetaData.getApiKey();
|
||||
request.setURI(new URI(uri));
|
||||
}
|
||||
catch(URISyntaxException e)
|
||||
{
|
||||
throw (new QException("Error setting authorization query parameter", e));
|
||||
}
|
||||
}
|
||||
case API_KEY_QUERY_PARAM -> addApiKeyQueryParamToRequest(request);
|
||||
case CUSTOM ->
|
||||
{
|
||||
handleCustomAuthorization(request);
|
||||
@ -761,6 +748,35 @@ public class BaseAPIActionUtil
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected void addApiKeyQueryParamToRequest(HttpRequestBase request) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
String uri = request.getURI().toString();
|
||||
String pair = backendMetaData.getApiKeyQueryParamName() + "=" + backendMetaData.getApiKey();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// avoid re-adding the name=value pair if it's already there (e.g., for a retry) //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
if(!uri.contains(pair))
|
||||
{
|
||||
uri += (uri.contains("?") ? "&" : "?");
|
||||
uri += pair;
|
||||
}
|
||||
|
||||
request.setURI(new URI(uri));
|
||||
}
|
||||
catch(URISyntaxException e)
|
||||
{
|
||||
throw (new QException("Error setting authorization query parameter", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1210,39 +1226,11 @@ public class BaseAPIActionUtil
|
||||
return;
|
||||
}
|
||||
|
||||
String requestBody = null;
|
||||
if(request instanceof HttpEntityEnclosingRequest entityRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestBody = StringUtils.join("\n", IOUtils.readLines(entityRequest.getEntity().getContent(), StandardCharsets.UTF_8));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// leave it null...
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// mask api keys in query strings //
|
||||
////////////////////////////////////
|
||||
String url = request.getURI().toString();
|
||||
if(backendMetaData.getAuthorizationType().equals(AuthorizationType.API_KEY_QUERY_PARAM))
|
||||
{
|
||||
url = url.replaceFirst(backendMetaData.getApiKey(), "******");
|
||||
}
|
||||
OutboundAPILog outboundAPILog = generateOutboundApiLogRecord(request, response);
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(table.getName());
|
||||
insertInput.setRecords(List.of(new OutboundAPILog()
|
||||
.withMethod(request.getMethod())
|
||||
.withUrl(url)
|
||||
.withTimestamp(Instant.now())
|
||||
.withRequestBody(requestBody)
|
||||
.withStatusCode(response.getStatusCode())
|
||||
.withResponseBody(response.getContent())
|
||||
.toQRecord()
|
||||
));
|
||||
insertInput.setRecords(List.of(outboundAPILog.toQRecord()));
|
||||
new InsertAction().executeAsync(insertInput);
|
||||
}
|
||||
catch(Exception e)
|
||||
@ -1253,6 +1241,44 @@ public class BaseAPIActionUtil
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public OutboundAPILog generateOutboundApiLogRecord(HttpRequestBase request, QHttpResponse response)
|
||||
{
|
||||
String requestBody = null;
|
||||
if(request instanceof HttpEntityEnclosingRequest entityRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestBody = StringUtils.join("\n", IOUtils.readLines(entityRequest.getEntity().getContent(), StandardCharsets.UTF_8));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// leave it null...
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// mask api keys in query strings //
|
||||
////////////////////////////////////
|
||||
String url = request.getURI().toString();
|
||||
if(backendMetaData.getAuthorizationType().equals(AuthorizationType.API_KEY_QUERY_PARAM))
|
||||
{
|
||||
url = url.replaceAll(backendMetaData.getApiKey(), "******");
|
||||
}
|
||||
|
||||
return new OutboundAPILog()
|
||||
.withMethod(request.getMethod())
|
||||
.withUrl(url)
|
||||
.withTimestamp(Instant.now())
|
||||
.withRequestBody(requestBody)
|
||||
.withStatusCode(response.getStatusCode())
|
||||
.withResponseBody(response.getContent());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -61,6 +61,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeConsumer;
|
||||
import com.kingsrook.qqq.backend.module.api.BaseTest;
|
||||
import com.kingsrook.qqq.backend.module.api.TestUtils;
|
||||
import com.kingsrook.qqq.backend.module.api.exceptions.RateLimitException;
|
||||
@ -74,6 +75,7 @@ import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -868,6 +870,72 @@ class BaseAPIActionUtilTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testAuthorizationApiKeyQueryParam() throws QException
|
||||
{
|
||||
APIBackendMetaData backend = (APIBackendMetaData) QContext.getQInstance().getBackend(TestUtils.MOCK_BACKEND_NAME);
|
||||
backend.setAuthorizationType(AuthorizationType.API_KEY_QUERY_PARAM);
|
||||
backend.setApiKeyQueryParamName("apikey");
|
||||
backend.setApiKey("9876-WXYZ");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this will make it not use the mock makeRequest method, //
|
||||
// but instead the mock executeHttpRequest, so we can test code from the base makeRequest //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
mockApiUtilsHelper.setUseMock(false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// we'll want to assert that the URL has the api query string - and just //
|
||||
// one copy of it (as we once had a bug where it got duplicated upon retry) //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
UnsafeConsumer<HttpRequestBase, Exception> asserter = request -> assertThat(request.getURI().toString())
|
||||
.contains("?apikey=9876-WXYZ")
|
||||
.doesNotContain("?apikey=9876-WXYZ&apikey=9876-WXYZ");
|
||||
|
||||
////////////////////////////////////////
|
||||
// queue up a 429, so we'll try-again //
|
||||
////////////////////////////////////////
|
||||
mockApiUtilsHelper.setMockRequestAsserter(asserter);
|
||||
mockApiUtilsHelper.enqueueMockResponse(new QHttpResponse().withStatusCode(429).withContent(""));
|
||||
|
||||
//////////////////////
|
||||
// queue a response //
|
||||
//////////////////////
|
||||
mockApiUtilsHelper.setMockRequestAsserter(asserter);
|
||||
mockApiUtilsHelper.enqueueMockResponse("""
|
||||
{"id": 3, "name": "Bart"},
|
||||
""");
|
||||
|
||||
GetOutput getOutput = runSimpleGetAction();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGenerateOutboundApiLogRecord() throws QException
|
||||
{
|
||||
APIBackendMetaData backend = (APIBackendMetaData) QContext.getQInstance().getBackend(TestUtils.MOCK_BACKEND_NAME);
|
||||
backend.setAuthorizationType(AuthorizationType.API_KEY_QUERY_PARAM);
|
||||
backend.setApiKeyQueryParamName("apikey");
|
||||
backend.setApiKey("9876-WXYZ");
|
||||
|
||||
MockApiActionUtils mockApiActionUtils = new MockApiActionUtils();
|
||||
mockApiActionUtils.setBackendMetaData(backend);
|
||||
OutboundAPILog outboundAPILog = mockApiActionUtils.generateOutboundApiLogRecord(new HttpGet("...?apikey=9876-WXYZ"), new QHttpResponse());
|
||||
|
||||
assertThat(outboundAPILog.getUrl())
|
||||
.doesNotContain("9876-WXYZ")
|
||||
.contains("?apikey=*****");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user