mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial WIP Checkpoint of auth0 userSessions
This commit is contained in:
@ -84,7 +84,7 @@ public class QContext
|
|||||||
actionStackThreadLocal.get().add(actionInput);
|
actionStackThreadLocal.get().add(actionInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!qInstance.getHasBeenValidated())
|
if(qInstance != null && !qInstance.getHasBeenValidated())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,6 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
private String auth0ClientSecretField;
|
private String auth0ClientSecretField;
|
||||||
private Serializable qqqRecordIdField;
|
private Serializable qqqRecordIdField;
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// fields on the accessToken table //
|
// fields on the accessToken table //
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
@ -70,6 +69,14 @@ public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
|||||||
private String qqqApiKeyField;
|
private String qqqApiKeyField;
|
||||||
private String expiresInSecondsField;
|
private String expiresInSecondsField;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// table for storing user sessions, and field names we work with on that table //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private String userSessionTableName;
|
||||||
|
private String userSessionUuidField;
|
||||||
|
private String userSessionUserIdField;
|
||||||
|
private String userSessionAccessTokenField;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -33,7 +33,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
|
||||||
import com.auth0.client.auth.AuthAPI;
|
import com.auth0.client.auth.AuthAPI;
|
||||||
import com.auth0.exception.Auth0Exception;
|
import com.auth0.exception.Auth0Exception;
|
||||||
import com.auth0.json.auth.TokenHolder;
|
import com.auth0.json.auth.TokenHolder;
|
||||||
@ -52,6 +51,7 @@ 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.actions.tables.UpdateAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.CapturedContext;
|
||||||
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;
|
||||||
@ -68,11 +68,11 @@ 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;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
|
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.model.UserSession;
|
||||||
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
|
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
|
||||||
import com.kingsrook.qqq.backend.core.state.SimpleStateKey;
|
import com.kingsrook.qqq.backend.core.state.SimpleStateKey;
|
||||||
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
|
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
|
||||||
@ -80,7 +80,6 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
|||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
@ -93,6 +92,18 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
** QQQ AuthenticationModule for working with Auth0.
|
||||||
|
**
|
||||||
|
** createSession can be called with the following fields in its context:
|
||||||
|
**
|
||||||
|
** System-User session use-case:
|
||||||
|
** 1: Takes in an "accessToken" (but doesn't store a userSession record).
|
||||||
|
**
|
||||||
|
** Web User session use-cases:
|
||||||
|
** 2: creates a new session (userSession record) by taking an "accessToken"
|
||||||
|
** 3: looks up an existing session (userSession record) by taking a "sessionUUID"
|
||||||
|
** 4: takes an "apiKey" (looked up in metaData.AccessTokenTableName - refreshing accessToken with auth0 if needed).
|
||||||
|
** 5: takes a "basicAuthString" (encoded username:password), which make a new accessToken in auth0
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
||||||
@ -104,14 +115,17 @@ 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 ACCESS_TOKEN_KEY = "accessToken";
|
||||||
public static final String API_KEY = "apiKey";
|
public static final String API_KEY = "apiKey"; // todo - look for users of this, see if we can change to use this constant; maybe move constants up?
|
||||||
public static final String BASIC_AUTH_KEY = "basicAuthString";
|
public static final String SESSION_UUID_KEY = "sessionUUID";
|
||||||
|
public static final String BASIC_AUTH_KEY = "basicAuthString"; // todo - look for users of this, see if we can change to use this constant; maybe move constants up?
|
||||||
|
|
||||||
public static final String TOKEN_NOT_PROVIDED_ERROR = "Access Token was not provided";
|
public static final String DO_STORE_USER_SESSION_KEY = "doStoreUserSession";
|
||||||
public static final String COULD_NOT_DECODE_ERROR = "Unable to decode access token";
|
|
||||||
public static final String EXPIRED_TOKEN_ERROR = "Token has expired";
|
static final String TOKEN_NOT_PROVIDED_ERROR = "Access Token was not provided";
|
||||||
public static final String INVALID_TOKEN_ERROR = "An invalid token was provided";
|
static final String COULD_NOT_DECODE_ERROR = "Unable to decode access token";
|
||||||
|
static final String EXPIRED_TOKEN_ERROR = "Token has expired";
|
||||||
|
static final String INVALID_TOKEN_ERROR = "An invalid token was provided";
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -149,94 +163,105 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
@Override
|
@Override
|
||||||
public QSession createSession(QInstance qInstance, Map<String, String> context) throws QAuthenticationException
|
public QSession createSession(QInstance qInstance, Map<String, String> context) throws QAuthenticationException
|
||||||
{
|
{
|
||||||
Auth0AuthenticationMetaData metaData = (Auth0AuthenticationMetaData) qInstance.getAuthentication();
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
// check if we are processing a Basic Auth Session first //
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
if(context.containsKey(BASIC_AUTH_KEY))
|
|
||||||
{
|
|
||||||
AuthAPI auth = AuthAPI.newBuilder(metaData.getBaseUrl(), metaData.getClientId(), metaData.getClientSecret()).build();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
/////////////////////////////////////////////////
|
|
||||||
// decode the credentials from the header auth //
|
|
||||||
/////////////////////////////////////////////////
|
|
||||||
String base64Credentials = context.get(BASIC_AUTH_KEY).trim();
|
|
||||||
String accessToken = getAccessTokenFromBase64BasicAuthCredentials(metaData, auth, base64Credentials);
|
|
||||||
context.put(AUTH0_ACCESS_TOKEN_KEY, accessToken);
|
|
||||||
}
|
|
||||||
catch(Auth0Exception e)
|
|
||||||
{
|
|
||||||
////////////////
|
|
||||||
// ¯\_(ツ)_/¯ //
|
|
||||||
////////////////
|
|
||||||
String message = "Error handling basic authentication: " + e.getMessage();
|
|
||||||
LOG.error(message, e);
|
|
||||||
throw (new QAuthenticationException(message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// get the jwt id or qqq translated token from the context object //
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
String accessToken = context.get(AUTH0_ACCESS_TOKEN_KEY);
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// check to see if the session id is a UUID, if so, that means we need to look up the 'actual' token in the access_token table //
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
if(accessToken != null && StringUtils.isUUID(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)
|
|
||||||
{
|
|
||||||
LOG.warn(TOKEN_NOT_PROVIDED_ERROR);
|
|
||||||
throw (new QAuthenticationException(TOKEN_NOT_PROVIDED_ERROR));
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// decode the token locally to make sure it is valid and to look at when it expires //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Auth0AuthenticationMetaData metaData = (Auth0AuthenticationMetaData) qInstance.getAuthentication();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if the context contains an access token, then create a new session based on that token. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
String accessToken = null;
|
||||||
|
if(CollectionUtils.containsKeyWithNonNullValue(context, ACCESS_TOKEN_KEY))
|
||||||
|
{
|
||||||
|
accessToken = context.get(ACCESS_TOKEN_KEY);
|
||||||
|
QSession qSession = buildAndValidateSession(qInstance, accessToken);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// build & store userSession db record, if requested to do so //
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
if(CollectionUtils.containsKeyWithNonNullValue(context, DO_STORE_USER_SESSION_KEY))
|
||||||
|
{
|
||||||
|
insertUserSession(qInstance, accessToken, qSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
else if(CollectionUtils.containsKeyWithNonNullValue(context, BASIC_AUTH_KEY))
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Process a basic auth (username:password) //
|
||||||
|
// by getting an access token from auth0 (re-using from state provider if possible) //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
AuthAPI auth = AuthAPI.newBuilder(metaData.getBaseUrl(), metaData.getClientId(), metaData.getClientSecret()).build();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// decode the credentials from the header auth //
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
String base64Credentials = context.get(BASIC_AUTH_KEY).trim();
|
||||||
|
accessToken = getAccessTokenFromBase64BasicAuthCredentials(metaData, auth, base64Credentials);
|
||||||
|
}
|
||||||
|
catch(Auth0Exception e)
|
||||||
|
{
|
||||||
|
////////////////
|
||||||
|
// ¯\_(ツ)_/¯ //
|
||||||
|
////////////////
|
||||||
|
String message = "Error handling basic authentication: " + e.getMessage();
|
||||||
|
LOG.error(message, e);
|
||||||
|
throw (new QAuthenticationException(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(CollectionUtils.containsKeyWithNonNullValue(context, API_KEY))
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// process an api key - looks up client application token (creating token if needed) //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
String apiKey = context.get(API_KEY);
|
||||||
|
if(apiKey != null)
|
||||||
|
{
|
||||||
|
accessToken = getAccessTokenFromApiKey(metaData, apiKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(CollectionUtils.containsKeyWithNonNullValue(context, SESSION_UUID_KEY))
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// process a sessionUUID - looks up userSession record - cannot create token this way. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
String sessionUUID = context.get(SESSION_UUID_KEY);
|
||||||
|
if(sessionUUID != null)
|
||||||
|
{
|
||||||
|
accessToken = getAccessTokenFromSessionUUID(metaData, sessionUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* todo confirm this is deprecated
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// check to see if the session id is a UUID, if so, that means we need to look up the 'actual' token in the access_token table //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(accessToken != null && StringUtils.isUUID(accessToken))
|
||||||
|
{
|
||||||
|
accessToken = lookupActualAccessToken(metaData, accessToken);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// if token wasn't found by now, give up //
|
||||||
|
///////////////////////////////////////////
|
||||||
|
if(accessToken == null)
|
||||||
|
{
|
||||||
|
LOG.warn(TOKEN_NOT_PROVIDED_ERROR);
|
||||||
|
throw (new QAuthenticationException(TOKEN_NOT_PROVIDED_ERROR));
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
// try to build session to see if still valid //
|
// try to build session to see if still valid //
|
||||||
// then call method to check more session validity //
|
// then call method to check more session validity //
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
QSession qSession = buildQSessionFromToken(accessToken, qInstance);
|
return buildAndValidateSession(qInstance, accessToken);
|
||||||
if(isSessionValid(qInstance, qSession))
|
}
|
||||||
{
|
catch(QAuthenticationException qae)
|
||||||
return (qSession);
|
{
|
||||||
}
|
throw (qae);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// if we make it here it means we have never validated this token or its been a long //
|
|
||||||
// enough duration so we need to re-verify the token //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
qSession = revalidateTokenAndBuildSession(qInstance, accessToken);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// put now into state so we dont check until next interval passes //
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
StateProviderInterface spi = getStateProvider();
|
|
||||||
SimpleStateKey<String> key = new SimpleStateKey<>(qSession.getIdReference());
|
|
||||||
spi.put(key, Instant.now());
|
|
||||||
|
|
||||||
return (qSession);
|
|
||||||
}
|
}
|
||||||
catch(JWTDecodeException jde)
|
catch(JWTDecodeException jde)
|
||||||
{
|
{
|
||||||
@ -272,6 +297,61 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Insert a session as a new record into userSession table
|
||||||
|
*******************************************************************************/
|
||||||
|
private void insertUserSession(QInstance qInstance, String accessToken, QSession qSession) throws QException
|
||||||
|
{
|
||||||
|
CapturedContext capturedContext = QContext.capture();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QContext.init(qInstance, null);
|
||||||
|
QContext.setQSession(getChickenAndEggSession());
|
||||||
|
|
||||||
|
UserSession userSession = new UserSession()
|
||||||
|
.withUuid(qSession.getUuid())
|
||||||
|
.withUserId(qSession.getUser().getIdReference())
|
||||||
|
.withAccessToken(accessToken);
|
||||||
|
|
||||||
|
new InsertAction().execute(new InsertInput(UserSession.TABLE_NAME).withRecordEntity(userSession));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
QContext.init(capturedContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QSession buildAndValidateSession(QInstance qInstance, String accessToken) throws JwkException
|
||||||
|
{
|
||||||
|
QSession qSession = buildQSessionFromToken(accessToken, qInstance);
|
||||||
|
if(isSessionValid(qInstance, qSession))
|
||||||
|
{
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if we make it here it means we have never validated this token or it has been a long //
|
||||||
|
// enough duration so we need to re-verify the token //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
qSession = revalidateTokenAndBuildSession(qInstance, accessToken);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// put now into state so we don't check until next interval passes //
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
StateProviderInterface spi = getStateProvider();
|
||||||
|
SimpleStateKey<String> key = new SimpleStateKey<>(qSession.getIdReference());
|
||||||
|
spi.put(key, Instant.now());
|
||||||
|
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -299,7 +379,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
|
byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
|
||||||
String credentials = new String(credDecoded, StandardCharsets.UTF_8);
|
String credentials = new String(credDecoded, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
String accessToken = getAccessTokenFromAuth0(metaData, auth, credentials);
|
String accessToken = getAccessTokenForUsernameAndPasswordFromAuth0(metaData, auth, credentials);
|
||||||
stateProvider.put(accessTokenStateKey, accessToken);
|
stateProvider.put(accessTokenStateKey, accessToken);
|
||||||
stateProvider.put(timestampStateKey, Instant.now());
|
stateProvider.put(timestampStateKey, Instant.now());
|
||||||
return (accessToken);
|
return (accessToken);
|
||||||
@ -310,7 +390,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected String getAccessTokenFromAuth0(Auth0AuthenticationMetaData metaData, AuthAPI auth, String credentials) throws Auth0Exception
|
protected String getAccessTokenForUsernameAndPasswordFromAuth0(Auth0AuthenticationMetaData metaData, AuthAPI auth, String credentials) throws Auth0Exception
|
||||||
{
|
{
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// call auth0 with a login request //
|
// call auth0 with a login request //
|
||||||
@ -620,75 +700,11 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** create a new auth0 access token
|
** make http request to Auth0 for a new access token for an application - e.g.,
|
||||||
|
** with a clientId and clientSecret as params
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public String createAccessToken(QAuthenticationMetaData metaData, String clientId, String clientSecret) throws AccessTokenException
|
public JSONObject requestAccessTokenForClientIdAndSecretFromAuth0(Auth0AuthenticationMetaData auth0MetaData, String clientId, String clientSecret) throws AccessTokenException
|
||||||
{
|
|
||||||
QSession sessionBefore = QContext.getQSession();
|
|
||||||
Auth0AuthenticationMetaData auth0MetaData = (Auth0AuthenticationMetaData) metaData;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QContext.setQSession(getChickenAndEggSession());
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// fetch the application from database, will throw accesstokenexception if not found //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
QRecord clientAuth0Application = getClientAuth0Application(auth0MetaData, clientId);
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// request access token from auth0 if exception is not thrown, that means 200OK, we want to //
|
|
||||||
// store the actual access token in the database, and return a unique value //
|
|
||||||
// back to the user which will be what they use on subseqeunt requests (because token too big) //
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
JSONObject accessTokenData = requestAccessTokenFromAuth0(auth0MetaData, clientId, clientSecret);
|
|
||||||
|
|
||||||
Integer expiresInSeconds = accessTokenData.getInt("expires_in");
|
|
||||||
String accessToken = accessTokenData.getString("access_token");
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
/////////////////////////////////
|
|
||||||
// store the details in the db //
|
|
||||||
/////////////////////////////////
|
|
||||||
QRecord accessTokenRecord = new QRecord()
|
|
||||||
.withValue(auth0MetaData.getClientAuth0ApplicationIdField(), clientAuth0Application.getValue("id"))
|
|
||||||
.withValue(auth0MetaData.getAuth0AccessTokenField(), accessToken)
|
|
||||||
.withValue(auth0MetaData.getQqqAccessTokenField(), uuid)
|
|
||||||
.withValue(auth0MetaData.getExpiresInSecondsField(), expiresInSeconds);
|
|
||||||
InsertInput input = new InsertInput();
|
|
||||||
input.setTableName(auth0MetaData.getAccessTokenTableName());
|
|
||||||
input.setRecords(List.of(accessTokenRecord));
|
|
||||||
new InsertAction().execute(input);
|
|
||||||
|
|
||||||
//////////////////////////////////
|
|
||||||
// update and send the response //
|
|
||||||
//////////////////////////////////
|
|
||||||
accessTokenData.put("access_token", uuid);
|
|
||||||
accessTokenData.remove("scope");
|
|
||||||
return (accessTokenData.toString());
|
|
||||||
}
|
|
||||||
catch(AccessTokenException ate)
|
|
||||||
{
|
|
||||||
throw (ate);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
throw (new AccessTokenException(e.getMessage(), e));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
QContext.setQSession(sessionBefore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** make http request to Auth0 for a new access token
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public JSONObject requestAccessTokenFromAuth0(Auth0AuthenticationMetaData auth0MetaData, String clientId, String clientSecret) throws AccessTokenException
|
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
// make a request to Auth0 using the client_id and client_secret //
|
// make a request to Auth0 using the client_id and client_secret //
|
||||||
@ -776,6 +792,63 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Look up access_token from session UUID
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String getAccessTokenFromSessionUUID(Auth0AuthenticationMetaData metaData, String sessionUUID) throws QAuthenticationException
|
||||||
|
{
|
||||||
|
String accessToken = null;
|
||||||
|
QSession beforeSession = QContext.getQSession();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QContext.setQSession(getChickenAndEggSession());
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// query for the user session record //
|
||||||
|
///////////////////////////////////////
|
||||||
|
QRecord userSessionRecord = new GetAction().executeForRecord(new GetInput(UserSession.TABLE_NAME)
|
||||||
|
.withUniqueKey(Map.of("uuid", sessionUUID))
|
||||||
|
.withShouldMaskPasswords(false)
|
||||||
|
.withShouldOmitHiddenFields(false));
|
||||||
|
|
||||||
|
if(userSessionRecord != null)
|
||||||
|
{
|
||||||
|
accessToken = userSessionRecord.getValueString("accessToken");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// decode the accessToken and make sure it is not expired //
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
if(accessToken != null)
|
||||||
|
{
|
||||||
|
DecodedJWT jwt = JWT.decode(accessToken);
|
||||||
|
if(jwt.getExpiresAtAsInstant().isBefore(Instant.now()))
|
||||||
|
{
|
||||||
|
throw (new QAuthenticationException("accessToken is expired"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
throw (qae);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error looking up userSession by sessionUUID", e);
|
||||||
|
throw (new QAuthenticationException("Error looking up userSession by sessionUUID", e));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
QContext.setQSession(beforeSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Look up access_token from api key
|
** Look up access_token from api key
|
||||||
**
|
**
|
||||||
@ -841,7 +914,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
// store the actual access token in the database, and return a unique value //
|
// store the actual access token in the database, and return a unique value //
|
||||||
// back to the user which will be what they use on subsequent requests (because token too big) //
|
// back to the user which will be what they use on subsequent requests (because token too big) //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
JSONObject accessTokenData = requestAccessTokenFromAuth0(metaData, clientId, clientSecret);
|
JSONObject accessTokenData = requestAccessTokenForClientIdAndSecretFromAuth0(metaData, clientId, clientSecret);
|
||||||
|
|
||||||
Integer expiresInSeconds = accessTokenData.getInt("expires_in");
|
Integer expiresInSeconds = accessTokenData.getInt("expires_in");
|
||||||
accessToken = accessTokenData.getString("access_token");
|
accessToken = accessTokenData.getString("access_token");
|
||||||
@ -869,28 +942,4 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
return (accessToken);
|
return (accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Look up client_auth0_application record, return if found.
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
QRecord getClientAuth0Application(Auth0AuthenticationMetaData metaData, String clientId) throws QException
|
|
||||||
{
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// try to look up existing auth0 application from database, insert one if not found //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
QueryInput queryInput = new QueryInput();
|
|
||||||
queryInput.setTableName(metaData.getClientAuth0ApplicationTableName());
|
|
||||||
queryInput.setFilter(new QQueryFilter(new QFilterCriteria(metaData.getAuth0ClientIdField(), QCriteriaOperator.EQUALS, clientId)));
|
|
||||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
|
||||||
|
|
||||||
if(CollectionUtils.nullSafeHasContents(queryOutput.getRecords()))
|
|
||||||
{
|
|
||||||
return (queryOutput.getRecords().get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw (new AccessTokenException("This client has not been configured to use the API.", HttpStatus.SC_UNAUTHORIZED));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.authentication.implementations.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.audits.QAuditRules;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.model.UserSession;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Meta Data Producer for UserSession
|
||||||
|
*******************************************************************************/
|
||||||
|
public class UserSessionMetaDataProducer extends MetaDataProducer<QTableMetaData>
|
||||||
|
{
|
||||||
|
private final String backendName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSessionMetaDataProducer(String backendName)
|
||||||
|
{
|
||||||
|
this.backendName = backendName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData tableMetaData = new QTableMetaData()
|
||||||
|
.withName(UserSession.TABLE_NAME)
|
||||||
|
.withBackendName(backendName)
|
||||||
|
.withRecordLabelFormat("%s")
|
||||||
|
.withRecordLabelFields("id")
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withUniqueKey(new UniqueKey("uuid"))
|
||||||
|
.withFieldsFromEntity(UserSession.class)
|
||||||
|
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.NONE));
|
||||||
|
return tableMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.authentication.implementations.model;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** QRecord Entity for UserSession table
|
||||||
|
*******************************************************************************/
|
||||||
|
public class UserSession extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "userSession";
|
||||||
|
|
||||||
|
@QField(isEditable = false)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField(isEditable = false)
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField(isEditable = false)
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField(isEditable = false, isHidden = true, maxLength = 40, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
@QField(isEditable = false, isHidden = true)
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
@QField(isEditable = false, maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Default constructor
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor that takes a QRecord
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession(QRecord record)
|
||||||
|
{
|
||||||
|
populateFromQRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return (this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return (this.createDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return (this.modifyDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for uuid
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getUuid()
|
||||||
|
{
|
||||||
|
return (this.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for uuid
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setUuid(String uuid)
|
||||||
|
{
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for uuid
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withUuid(String uuid)
|
||||||
|
{
|
||||||
|
this.uuid = uuid;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for accessToken
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getAccessToken()
|
||||||
|
{
|
||||||
|
return (this.accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for accessToken
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAccessToken(String accessToken)
|
||||||
|
{
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for accessToken
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withAccessToken(String accessToken)
|
||||||
|
{
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for userId
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getUserId()
|
||||||
|
{
|
||||||
|
return (this.userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for userId
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setUserId(String userId)
|
||||||
|
{
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for userId
|
||||||
|
*******************************************************************************/
|
||||||
|
public UserSession withUserId(String userId)
|
||||||
|
{
|
||||||
|
this.userId = userId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -663,4 +663,19 @@ public class CollectionUtils
|
|||||||
return (output);
|
return (output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static <K> boolean containsKeyWithNonNullValue(Map<K, ?> map, K key)
|
||||||
|
{
|
||||||
|
if(map == null)
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (map.containsKey(key) && map.get(key) != null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ import com.kingsrook.qqq.backend.core.state.SimpleStateKey;
|
|||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.AUTH0_ACCESS_TOKEN_KEY;
|
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.ACCESS_TOKEN_KEY;
|
||||||
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.BASIC_AUTH_KEY;
|
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.BASIC_AUTH_KEY;
|
||||||
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.COULD_NOT_DECODE_ERROR;
|
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.COULD_NOT_DECODE_ERROR;
|
||||||
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.EXPIRED_TOKEN_ERROR;
|
import static com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule.EXPIRED_TOKEN_ERROR;
|
||||||
@ -143,7 +143,7 @@ public class Auth0AuthenticationModuleTest extends BaseTest
|
|||||||
public void testInvalidToken()
|
public void testInvalidToken()
|
||||||
{
|
{
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
context.put(AUTH0_ACCESS_TOKEN_KEY, INVALID_TOKEN);
|
context.put(ACCESS_TOKEN_KEY, INVALID_TOKEN);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -167,7 +167,7 @@ public class Auth0AuthenticationModuleTest extends BaseTest
|
|||||||
public void testUndecodableToken()
|
public void testUndecodableToken()
|
||||||
{
|
{
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
context.put(AUTH0_ACCESS_TOKEN_KEY, UNDECODABLE_TOKEN);
|
context.put(ACCESS_TOKEN_KEY, UNDECODABLE_TOKEN);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -191,7 +191,7 @@ public class Auth0AuthenticationModuleTest extends BaseTest
|
|||||||
public void testProperlyFormattedButExpiredToken()
|
public void testProperlyFormattedButExpiredToken()
|
||||||
{
|
{
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
context.put(AUTH0_ACCESS_TOKEN_KEY, EXPIRED_TOKEN);
|
context.put(ACCESS_TOKEN_KEY, EXPIRED_TOKEN);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -236,7 +236,7 @@ public class Auth0AuthenticationModuleTest extends BaseTest
|
|||||||
public void testNullToken()
|
public void testNullToken()
|
||||||
{
|
{
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
context.put(AUTH0_ACCESS_TOKEN_KEY, null);
|
context.put(ACCESS_TOKEN_KEY, null);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -267,7 +267,7 @@ public class Auth0AuthenticationModuleTest extends BaseTest
|
|||||||
auth0Spy.createSession(qInstance, context);
|
auth0Spy.createSession(qInstance, context);
|
||||||
auth0Spy.createSession(qInstance, context);
|
auth0Spy.createSession(qInstance, context);
|
||||||
auth0Spy.createSession(qInstance, context);
|
auth0Spy.createSession(qInstance, context);
|
||||||
verify(auth0Spy, times(1)).getAccessTokenFromAuth0(any(), any(), any());
|
verify(auth0Spy, times(1)).getAccessTokenForUsernameAndPasswordFromAuth0(any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ import java.io.Serializable;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -58,7 +57,6 @@ import com.kingsrook.qqq.api.model.openapi.HttpMethod;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
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.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.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.exceptions.QModuleDispatchException;
|
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||||
@ -75,15 +73,12 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
|||||||
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.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.branding.QBrandingMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.branding.QBrandingMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
@ -137,11 +132,6 @@ public class QJavalinApiHandler
|
|||||||
{
|
{
|
||||||
return (() ->
|
return (() ->
|
||||||
{
|
{
|
||||||
/////////////////////////////
|
|
||||||
// authentication endpoint //
|
|
||||||
/////////////////////////////
|
|
||||||
ApiBuilder.post("/api/oauth/token", QJavalinApiHandler::handleAuthorization);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////
|
///////////////////////////////////////////////
|
||||||
// static endpoints to support rapidoc pages //
|
// static endpoints to support rapidoc pages //
|
||||||
///////////////////////////////////////////////
|
///////////////////////////////////////////////
|
||||||
@ -583,101 +573,6 @@ public class QJavalinApiHandler
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private static void handleAuthorization(Context context)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// clientId & clientSecret may either be provided as formParams, or in an Authorization: Basic header //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
String clientId;
|
|
||||||
String clientSecret;
|
|
||||||
String authorizationHeader = context.header("Authorization");
|
|
||||||
if(authorizationHeader != null && authorizationHeader.startsWith("Basic "))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] credDecoded = Base64.getDecoder().decode(authorizationHeader.replace("Basic ", ""));
|
|
||||||
String credentials = new String(credDecoded, StandardCharsets.UTF_8);
|
|
||||||
String[] parts = credentials.split(":", 2);
|
|
||||||
clientId = parts[0];
|
|
||||||
clientSecret = parts[1];
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
context.status(HttpStatus.BAD_REQUEST_400);
|
|
||||||
context.result("Could not parse client_id and client_secret from Basic Authorization header.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clientId = context.formParam("client_id");
|
|
||||||
if(clientId == null)
|
|
||||||
{
|
|
||||||
context.status(HttpStatus.BAD_REQUEST_400);
|
|
||||||
context.result("'client_id' must be provided.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clientSecret = context.formParam("client_secret");
|
|
||||||
if(clientSecret == null)
|
|
||||||
{
|
|
||||||
context.status(HttpStatus.BAD_REQUEST_400);
|
|
||||||
context.result("'client_secret' must be provided.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// get the auth0 authentication module from qInstance //
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
Auth0AuthenticationMetaData metaData = (Auth0AuthenticationMetaData) qInstance.getAuthentication();
|
|
||||||
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
|
|
||||||
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// make call to get access token data, if no exception thrown, assume 200 OK and return //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
QContext.init(qInstance, null); // hmm...
|
|
||||||
String accessToken = authenticationModule.createAccessToken(metaData, clientId, clientSecret);
|
|
||||||
context.status(HttpStatus.Code.OK.getCode());
|
|
||||||
context.result(accessToken);
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
|
||||||
}
|
|
||||||
catch(AccessTokenException aae)
|
|
||||||
{
|
|
||||||
LOG.info("Error getting api access token", aae, logPair("clientId", clientId));
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// if the exception has a status code, then return that code and message //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
if(aae.getStatusCode() != null)
|
|
||||||
{
|
|
||||||
context.status(aae.getStatusCode());
|
|
||||||
context.result(aae.getMessage());
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// if no code, throw and handle like other exceptions //
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
throw (aae);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
handleException(context, e);
|
|
||||||
QJavalinAccessLogger.logEndFail(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -113,6 +113,7 @@ import com.kingsrook.qqq.backend.core.model.session.QSession;
|
|||||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QStatusMessage;
|
import com.kingsrook.qqq.backend.core.model.statusmessages.QStatusMessage;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
@ -148,10 +149,10 @@ public class QJavalinImplementation
|
|||||||
{
|
{
|
||||||
private static final QLogger LOG = QLogger.getLogger(QJavalinImplementation.class);
|
private static final QLogger LOG = QLogger.getLogger(QJavalinImplementation.class);
|
||||||
|
|
||||||
public static final int SESSION_COOKIE_AGE = 60 * 60 * 24;
|
public static final int SESSION_COOKIE_AGE = 60 * 60 * 24;
|
||||||
public static final String SESSION_ID_COOKIE_NAME = "sessionId";
|
public static final String SESSION_ID_COOKIE_NAME = "sessionId";
|
||||||
public static final String BASIC_AUTH_NAME = "basicAuthString";
|
public static final String SESSION_UUID_COOKIE_NAME = "sessionUUID";
|
||||||
public static final String API_KEY_NAME = "apiKey";
|
public static final String API_KEY_NAME = "apiKey";
|
||||||
|
|
||||||
static QInstance qInstance;
|
static QInstance qInstance;
|
||||||
static QJavalinMetaData javalinMetaData;
|
static QJavalinMetaData javalinMetaData;
|
||||||
@ -329,6 +330,8 @@ public class QJavalinImplementation
|
|||||||
{
|
{
|
||||||
return (() ->
|
return (() ->
|
||||||
{
|
{
|
||||||
|
post("/manageSession", QJavalinImplementation::manageSession);
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// metadata routes //
|
// metadata routes //
|
||||||
/////////////////////
|
/////////////////////
|
||||||
@ -400,6 +403,36 @@ public class QJavalinImplementation
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void manageSession(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Map<?, ?> map = context.bodyAsClass(Map.class);
|
||||||
|
|
||||||
|
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
|
||||||
|
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication());
|
||||||
|
|
||||||
|
Map<String, String> authContext = new HashMap<>();
|
||||||
|
//? authContext.put("uuid", ValueUtils.getValueAsString(map.get("uuid")));
|
||||||
|
authContext.put(Auth0AuthenticationModule.ACCESS_TOKEN_KEY, ValueUtils.getValueAsString(map.get("accessToken")));
|
||||||
|
authContext.put(Auth0AuthenticationModule.DO_STORE_USER_SESSION_KEY, "true");
|
||||||
|
|
||||||
|
QSession session = authenticationModule.createSession(qInstance, authContext);
|
||||||
|
|
||||||
|
context.cookie(SESSION_UUID_COOKIE_NAME, session.getUuid(), SESSION_COOKIE_AGE);
|
||||||
|
context.result(JsonUtils.toJson(MapBuilder.of("uuid", session.getUuid())));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -442,10 +475,12 @@ public class QJavalinImplementation
|
|||||||
{
|
{
|
||||||
Map<String, String> authenticationContext = new HashMap<>();
|
Map<String, String> authenticationContext = new HashMap<>();
|
||||||
|
|
||||||
String sessionIdCookieValue = context.cookie(SESSION_ID_COOKIE_NAME);
|
// todo delete String sessionIdCookieValue = context.cookie(SESSION_ID_COOKIE_NAME);
|
||||||
|
String sessionUuidCookieValue = context.cookie(Auth0AuthenticationModule.SESSION_UUID_KEY);
|
||||||
String authorizationHeaderValue = context.header("Authorization");
|
String authorizationHeaderValue = context.header("Authorization");
|
||||||
String apiKeyHeaderValue = context.header("x-api-key");
|
String apiKeyHeaderValue = context.header("x-api-key");
|
||||||
|
|
||||||
|
/* todo - change to sessionUUID.
|
||||||
if(StringUtils.hasContent(sessionIdCookieValue))
|
if(StringUtils.hasContent(sessionIdCookieValue))
|
||||||
{
|
{
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
@ -453,6 +488,11 @@ public class QJavalinImplementation
|
|||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
authenticationContext.put(SESSION_ID_COOKIE_NAME, sessionIdCookieValue);
|
authenticationContext.put(SESSION_ID_COOKIE_NAME, sessionIdCookieValue);
|
||||||
}
|
}
|
||||||
|
else*/
|
||||||
|
if(StringUtils.hasContent(sessionUuidCookieValue))
|
||||||
|
{
|
||||||
|
authenticationContext.put(Auth0AuthenticationModule.SESSION_UUID_KEY, sessionUuidCookieValue);
|
||||||
|
}
|
||||||
else if(apiKeyHeaderValue != null)
|
else if(apiKeyHeaderValue != null)
|
||||||
{
|
{
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
@ -533,12 +573,12 @@ public class QJavalinImplementation
|
|||||||
if(authorizationHeaderValue.startsWith(basicPrefix))
|
if(authorizationHeaderValue.startsWith(basicPrefix))
|
||||||
{
|
{
|
||||||
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(basicPrefix, "");
|
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(basicPrefix, "");
|
||||||
authenticationContext.put(BASIC_AUTH_NAME, authorizationHeaderValue);
|
authenticationContext.put(Auth0AuthenticationModule.BASIC_AUTH_KEY, authorizationHeaderValue);
|
||||||
}
|
}
|
||||||
else if(authorizationHeaderValue.startsWith(bearerPrefix))
|
else if(authorizationHeaderValue.startsWith(bearerPrefix))
|
||||||
{
|
{
|
||||||
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(bearerPrefix, "");
|
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(bearerPrefix, "");
|
||||||
authenticationContext.put(SESSION_ID_COOKIE_NAME, authorizationHeaderValue);
|
authenticationContext.put(Auth0AuthenticationModule.ACCESS_TOKEN_KEY, authorizationHeaderValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -90,8 +90,6 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
|||||||
import io.github.cdimascio.dotenv.Dotenv;
|
import io.github.cdimascio.dotenv.Dotenv;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
import org.jline.reader.LineReader;
|
|
||||||
import org.jline.reader.LineReaderBuilder;
|
|
||||||
import org.jline.utils.Log;
|
import org.jline.utils.Log;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
import picocli.CommandLine.Model.CommandSpec;
|
import picocli.CommandLine.Model.CommandSpec;
|
||||||
@ -292,18 +290,7 @@ public class QPicoCliImplementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> authenticationContext = new HashMap<>();
|
Map<String, String> authenticationContext = new HashMap<>();
|
||||||
if(sessionId == null && authenticationModule instanceof Auth0AuthenticationModule)
|
authenticationContext.put(Auth0AuthenticationModule.ACCESS_TOKEN_KEY, sessionId);
|
||||||
{
|
|
||||||
LineReader lr = LineReaderBuilder.builder().build();
|
|
||||||
String tokenId = lr.readLine("Create a .env file with the contents of the Auth0 JWT Id Token in the variable 'SESSION_ID': \nPress enter once complete...");
|
|
||||||
dotenv = loadDotEnv();
|
|
||||||
if(dotenv.isPresent())
|
|
||||||
{
|
|
||||||
sessionId = dotenv.get().get("SESSION_ID");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticationContext.put("sessionId", sessionId);
|
|
||||||
|
|
||||||
// todo - does this need some per-provider logic actually? mmm...
|
// todo - does this need some per-provider logic actually? mmm...
|
||||||
session = authenticationModule.createSession(qInstance, authenticationContext);
|
session = authenticationModule.createSession(qInstance, authenticationContext);
|
||||||
|
Reference in New Issue
Block a user