mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Merge branch 'feature/CTLE-421-migrate-to-use-api-keys' into integration/sprint-25
This commit is contained in:
@ -334,6 +334,8 @@ public class GetAction
|
|||||||
queryInput.setIncludeAssociations(getInput.getIncludeAssociations());
|
queryInput.setIncludeAssociations(getInput.getIncludeAssociations());
|
||||||
queryInput.setAssociationNamesToInclude(getInput.getAssociationNamesToInclude());
|
queryInput.setAssociationNamesToInclude(getInput.getAssociationNamesToInclude());
|
||||||
queryInput.setShouldFetchHeavyFields(getInput.getShouldFetchHeavyFields());
|
queryInput.setShouldFetchHeavyFields(getInput.getShouldFetchHeavyFields());
|
||||||
|
queryInput.setShouldMaskPasswords(getInput.getShouldMaskPasswords());
|
||||||
|
queryInput.setShouldOmitHiddenFields(getInput.getShouldOmitHiddenFields());
|
||||||
|
|
||||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
private String applicationNameField;
|
private String applicationNameField;
|
||||||
private String auth0ClientIdField;
|
private String auth0ClientIdField;
|
||||||
private String auth0ClientSecretMaskedField;
|
private String auth0ClientSecretField;
|
||||||
private Serializable qqqRecordIdField;
|
private Serializable qqqRecordIdField;
|
||||||
|
|
||||||
|
|
||||||
@ -67,6 +67,7 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
private String clientAuth0ApplicationIdField;
|
private String clientAuth0ApplicationIdField;
|
||||||
private String auth0AccessTokenField;
|
private String auth0AccessTokenField;
|
||||||
private String qqqAccessTokenField;
|
private String qqqAccessTokenField;
|
||||||
|
private String qqqApiKeyField;
|
||||||
private String expiresInSecondsField;
|
private String expiresInSecondsField;
|
||||||
|
|
||||||
|
|
||||||
@ -387,40 +388,6 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Getter for auth0ClientSecretMaskedField
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public String getAuth0ClientSecretMaskedField()
|
|
||||||
{
|
|
||||||
return auth0ClientSecretMaskedField;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Setter for auth0ClientSecretMaskedField
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public void setAuth0ClientSecretMaskedField(String auth0ClientSecretMaskedField)
|
|
||||||
{
|
|
||||||
this.auth0ClientSecretMaskedField = auth0ClientSecretMaskedField;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Fluent setter for auth0ClientSecretMaskedField
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public Auth0AuthenticationMetaData withAuth0ClientSecretMaskedField(String auth0ClientSecretMaskedField)
|
|
||||||
{
|
|
||||||
this.auth0ClientSecretMaskedField = auth0ClientSecretMaskedField;
|
|
||||||
return (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for clientAuth0ApplicationIdField
|
** Getter for clientAuth0ApplicationIdField
|
||||||
**
|
**
|
||||||
@ -555,4 +522,66 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for qqqApiKeyField
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getQqqApiKeyField()
|
||||||
|
{
|
||||||
|
return (this.qqqApiKeyField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for qqqApiKeyField
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setQqqApiKeyField(String qqqApiKeyField)
|
||||||
|
{
|
||||||
|
this.qqqApiKeyField = qqqApiKeyField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for qqqApiKeyField
|
||||||
|
*******************************************************************************/
|
||||||
|
public Auth0AuthenticationMetaData withQqqApiKeyField(String qqqApiKeyField)
|
||||||
|
{
|
||||||
|
this.qqqApiKeyField = qqqApiKeyField;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for auth0ClientSecretField
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getAuth0ClientSecretField()
|
||||||
|
{
|
||||||
|
return (this.auth0ClientSecretField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for auth0ClientSecretField
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAuth0ClientSecretField(String auth0ClientSecretField)
|
||||||
|
{
|
||||||
|
this.auth0ClientSecretField = auth0ClientSecretField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for auth0ClientSecretField
|
||||||
|
*******************************************************************************/
|
||||||
|
public Auth0AuthenticationMetaData withAuth0ClientSecretField(String auth0ClientSecretField)
|
||||||
|
{
|
||||||
|
this.auth0ClientSecretField = auth0ClientSecretField;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,19 +48,23 @@ import com.auth0.jwt.exceptions.JWTVerificationException;
|
|||||||
import com.auth0.jwt.exceptions.TokenExpiredException;
|
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
import com.auth0.net.Response;
|
import com.auth0.net.Response;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.AccessTokenException;
|
import com.kingsrook.qqq.backend.core.exceptions.AccessTokenException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.Auth0AuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.authentication.Auth0AuthenticationMetaData;
|
||||||
@ -101,6 +105,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
public static final int ID_TOKEN_VALIDATION_INTERVAL_SECONDS = 1800;
|
public static final int ID_TOKEN_VALIDATION_INTERVAL_SECONDS = 1800;
|
||||||
|
|
||||||
public static final String AUTH0_ACCESS_TOKEN_KEY = "sessionId";
|
public static final String AUTH0_ACCESS_TOKEN_KEY = "sessionId";
|
||||||
|
public static final String API_KEY = "apiKey";
|
||||||
public static final String BASIC_AUTH_KEY = "basicAuthString";
|
public static final String BASIC_AUTH_KEY = "basicAuthString";
|
||||||
|
|
||||||
public static final String TOKEN_NOT_PROVIDED_ERROR = "Access Token was not provided";
|
public static final String TOKEN_NOT_PROVIDED_ERROR = "Access Token was not provided";
|
||||||
@ -185,6 +190,18 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
accessToken = lookupActualAccessToken(metaData, accessToken);
|
accessToken = lookupActualAccessToken(metaData, accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// if access token is still null, look for an api key //
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
if(accessToken == null)
|
||||||
|
{
|
||||||
|
String apiKey = context.get(API_KEY);
|
||||||
|
if(apiKey != null)
|
||||||
|
{
|
||||||
|
accessToken = getAccessTokenFromApiKey(metaData, apiKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(accessToken == null)
|
if(accessToken == null)
|
||||||
{
|
{
|
||||||
LOG.warn(TOKEN_NOT_PROVIDED_ERROR);
|
LOG.warn(TOKEN_NOT_PROVIDED_ERROR);
|
||||||
@ -603,7 +620,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Load an instance of the appropriate state provider
|
** create a new auth0 access token
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public String createAccessToken(QAuthenticationMetaData metaData, String clientId, String clientSecret) throws AccessTokenException
|
public String createAccessToken(QAuthenticationMetaData metaData, String clientId, String clientSecret) throws AccessTokenException
|
||||||
@ -759,6 +776,90 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Look up access_token from api key
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
String getAccessTokenFromApiKey(Auth0AuthenticationMetaData metaData, String apiKey)
|
||||||
|
{
|
||||||
|
String accessToken = null;
|
||||||
|
QSession beforeSession = QContext.getQSession();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QContext.setQSession(getChickenAndEggSession());
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// try to look up existing auth0 application from database, insert one if not found //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(metaData.getAccessTokenTableName());
|
||||||
|
queryInput.setShouldOmitHiddenFields(false);
|
||||||
|
queryInput.setShouldMaskPasswords(false);
|
||||||
|
queryInput.setFilter(new QQueryFilter(new QFilterCriteria(metaData.getQqqApiKeyField(), QCriteriaOperator.EQUALS, apiKey)));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(queryOutput.getRecords()))
|
||||||
|
{
|
||||||
|
QRecord clientAuth0ApiKey = queryOutput.getRecords().get(0);
|
||||||
|
accessToken = clientAuth0ApiKey.getValueString(metaData.getAuth0AccessTokenField());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// decode the accessToken and make sure it is not expired //
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
boolean needNewToken = true;
|
||||||
|
if(accessToken != null)
|
||||||
|
{
|
||||||
|
DecodedJWT jwt = JWT.decode(accessToken);
|
||||||
|
String payload = jwt.getPayload();
|
||||||
|
System.out.println("IOK");
|
||||||
|
needNewToken = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needNewToken)
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// get id/secret from the application record //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
GetInput getInput = new GetInput();
|
||||||
|
getInput.setTableName(metaData.getClientAuth0ApplicationTableName());
|
||||||
|
getInput.setShouldOmitHiddenFields(false);
|
||||||
|
getInput.setShouldMaskPasswords(false);
|
||||||
|
getInput.setPrimaryKey(clientAuth0ApiKey.getValueString(metaData.getClientAuth0ApplicationIdField()));
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// create a new access token //
|
||||||
|
///////////////////////////////
|
||||||
|
QRecord clientAuth0Application = new GetAction().execute(getInput).getRecord();
|
||||||
|
String clientId = clientAuth0Application.getValueString(metaData.getAuth0ClientIdField());
|
||||||
|
String clientSecret = clientAuth0Application.getValueString(metaData.getAuth0ClientSecretField());
|
||||||
|
accessToken = createAccessToken(metaData, clientId, clientSecret);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// update the api key record and store new access token //
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
clientAuth0ApiKey.setValue(metaData.getAuth0AccessTokenField(), accessToken);
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(metaData.getAccessTokenTableName());
|
||||||
|
updateInput.setRecords(List.of(clientAuth0ApiKey));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Could not find Auth0 access token for provided qqq API Key", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
QContext.setQSession(beforeSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Look up client_auth0_application record, return if found.
|
** Look up client_auth0_application record, return if found.
|
||||||
**
|
**
|
||||||
|
@ -134,9 +134,10 @@ public class QJavalinImplementation
|
|||||||
{
|
{
|
||||||
private static final QLogger LOG = QLogger.getLogger(QJavalinImplementation.class);
|
private static final QLogger LOG = QLogger.getLogger(QJavalinImplementation.class);
|
||||||
|
|
||||||
private static final int SESSION_COOKIE_AGE = 60 * 60 * 24;
|
public static final int SESSION_COOKIE_AGE = 60 * 60 * 24;
|
||||||
private static final String SESSION_ID_COOKIE_NAME = "sessionId";
|
public static final String SESSION_ID_COOKIE_NAME = "sessionId";
|
||||||
private static final String BASIC_AUTH_NAME = "basicAuthString";
|
public static final String BASIC_AUTH_NAME = "basicAuthString";
|
||||||
|
public static final String API_KEY_NAME = "apiKey";
|
||||||
|
|
||||||
static QInstance qInstance;
|
static QInstance qInstance;
|
||||||
static QJavalinMetaData javalinMetaData;
|
static QJavalinMetaData javalinMetaData;
|
||||||
@ -422,6 +423,7 @@ public class QJavalinImplementation
|
|||||||
|
|
||||||
String sessionIdCookieValue = context.cookie(SESSION_ID_COOKIE_NAME);
|
String sessionIdCookieValue = context.cookie(SESSION_ID_COOKIE_NAME);
|
||||||
String authorizationHeaderValue = context.header("Authorization");
|
String authorizationHeaderValue = context.header("Authorization");
|
||||||
|
String apiKeyHeaderValue = context.header("x-api-key");
|
||||||
|
|
||||||
if(StringUtils.hasContent(sessionIdCookieValue))
|
if(StringUtils.hasContent(sessionIdCookieValue))
|
||||||
{
|
{
|
||||||
@ -430,6 +432,14 @@ public class QJavalinImplementation
|
|||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
authenticationContext.put(SESSION_ID_COOKIE_NAME, sessionIdCookieValue);
|
authenticationContext.put(SESSION_ID_COOKIE_NAME, sessionIdCookieValue);
|
||||||
}
|
}
|
||||||
|
else if(apiKeyHeaderValue != null)
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// next, look for an api key header: //
|
||||||
|
// this will be used to look up auth0 values via an auth table //
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
authenticationContext.put(API_KEY_NAME, apiKeyHeaderValue);
|
||||||
|
}
|
||||||
else if(authorizationHeaderValue != null)
|
else if(authorizationHeaderValue != null)
|
||||||
{
|
{
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Reference in New Issue
Block a user