mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
QQQ-27: updates to allow Auth0 to be an authentication model in QQQ
This commit is contained in:
5
pom.xml
5
pom.xml
@ -53,6 +53,11 @@
|
|||||||
<!-- none, this is core. -->
|
<!-- none, this is core. -->
|
||||||
|
|
||||||
<!-- 3rd party deps specifically for this module -->
|
<!-- 3rd party deps specifically for this module -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>mvc-auth-commons</artifactId>
|
||||||
|
<version>[1.0, 2.0)</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Exception thrown while doing module-dispatch
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QAuthenticationException extends QException
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor of message
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QAuthenticationException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor of message & cause
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QAuthenticationException(String message, Throwable cause)
|
||||||
|
{
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ package com.kingsrook.qqq.backend.core.model.actions;
|
|||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
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.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.model.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Enum to define the possible authentication types
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public enum QAuthenticationType
|
||||||
|
{
|
||||||
|
AUTH_0("auth0"),
|
||||||
|
FULLY_ANONYMOUS("fullyAnonymous"),
|
||||||
|
MOCK("mock");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** enum constructor
|
||||||
|
*******************************************************************************/
|
||||||
|
QAuthenticationType(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -32,6 +32,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleVal
|
|||||||
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.processes.QStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||||
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.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
package com.kingsrook.qqq.backend.core.model.session;
|
package com.kingsrook.qqq.backend.core.model.session;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ import java.util.Map;
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class QSession
|
public class QSession implements Serializable
|
||||||
{
|
{
|
||||||
private String idReference;
|
private String idReference;
|
||||||
private QUser user;
|
private QUser user;
|
||||||
|
@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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;
|
||||||
|
|
||||||
|
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.auth0.jwk.Jwk;
|
||||||
|
import com.auth0.jwk.JwkException;
|
||||||
|
import com.auth0.jwk.JwkProvider;
|
||||||
|
import com.auth0.jwk.UrlJwkProvider;
|
||||||
|
import com.auth0.jwt.JWT;
|
||||||
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
|
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||||
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
|
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
|
import com.auth0.jwt.interfaces.JWTVerifier;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.Auth0AuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.state.AbstractStateKey;
|
||||||
|
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
||||||
|
{
|
||||||
|
private static final Logger logger = LogManager.getLogger(Auth0AuthenticationModule.class);
|
||||||
|
|
||||||
|
private static final int ID_TOKEN_VALIDATION_INTERVAL_SECONDS = 300;
|
||||||
|
|
||||||
|
public static final String AUTH0_ID_TOKEN_KEY = "qqq.idToken";
|
||||||
|
|
||||||
|
public static final String TOKEN_NOT_PROVIDED_ERROR = "Id Token was not provided";
|
||||||
|
public static final String COULD_NOT_DECODE_ERROR = "Unable to decode id token";
|
||||||
|
public static final String EXPIRED_TOKEN_ERROR = "Token has expired";
|
||||||
|
public static final String INVALID_TOKEN_ERROR = "An invalid token was provided";
|
||||||
|
|
||||||
|
|
||||||
|
private Instant now;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QSession createSession(QInstance qInstance, Map<String, String> context) throws QAuthenticationException
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// get the jwt id token from the context object //
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
String idToken = context.get(AUTH0_ID_TOKEN_KEY);
|
||||||
|
if(idToken == null)
|
||||||
|
{
|
||||||
|
////////////////////////////////
|
||||||
|
// could not decode the token //
|
||||||
|
////////////////////////////////
|
||||||
|
logger.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 to build session to see if still valid //
|
||||||
|
// then call method to check more session validity //
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
QSession qSession = buildQSessionFromToken(idToken);
|
||||||
|
if(isSessionValid(qSession))
|
||||||
|
{
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 = revalidateToken(qInstance, idToken);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// put now into state so we dont check until next interval passes //
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
StateProviderInterface spi = getStateProvider();
|
||||||
|
Auth0StateKey key = new Auth0StateKey(qSession.getIdReference());
|
||||||
|
spi.put(key, getNow());
|
||||||
|
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
catch(JWTDecodeException jde)
|
||||||
|
{
|
||||||
|
////////////////////////////////
|
||||||
|
// could not decode the token //
|
||||||
|
////////////////////////////////
|
||||||
|
logger.warn(COULD_NOT_DECODE_ERROR, jde);
|
||||||
|
throw (new QAuthenticationException(COULD_NOT_DECODE_ERROR));
|
||||||
|
}
|
||||||
|
catch(TokenExpiredException tee)
|
||||||
|
{
|
||||||
|
logger.info(EXPIRED_TOKEN_ERROR, tee);
|
||||||
|
throw (new QAuthenticationException(EXPIRED_TOKEN_ERROR));
|
||||||
|
}
|
||||||
|
catch(JWTVerificationException | JwkException jve)
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// token had invalid signature or claims //
|
||||||
|
///////////////////////////////////////////
|
||||||
|
logger.warn(INVALID_TOKEN_ERROR, jve);
|
||||||
|
throw (new QAuthenticationException(INVALID_TOKEN_ERROR));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
////////////////
|
||||||
|
// ¯\_(ツ)_/¯ //
|
||||||
|
////////////////
|
||||||
|
String message = "An unknown error occurred";
|
||||||
|
logger.error(message, e);
|
||||||
|
throw (new QAuthenticationException(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean isSessionValid(QSession session)
|
||||||
|
{
|
||||||
|
if(session == null)
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
StateProviderInterface spi = getStateProvider();
|
||||||
|
Auth0StateKey key = new Auth0StateKey(session.getIdReference());
|
||||||
|
if(spi.get(Instant.class, key).isPresent())
|
||||||
|
{
|
||||||
|
Instant lastTimeChecked = spi.get(Instant.class, key).get();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// returns negative int if less than compared duration, 0 if equal, positive int if greater than //
|
||||||
|
// - so this is basically saying, if the time between the last time we checked the token and //
|
||||||
|
// right now is more than ID_TOKEN_VALIDATION_INTERVAL_SECTIONS, then session needs revalidated //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
return (Duration.between(lastTimeChecked, getNow()).compareTo(Duration.ofSeconds(ID_TOKEN_VALIDATION_INTERVAL_SECONDS)) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** public method so that 'now' can be used for testing purposes
|
||||||
|
** - defaults to real 'now'
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getNow()
|
||||||
|
{
|
||||||
|
if(now == null)
|
||||||
|
{
|
||||||
|
now = Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (now);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** public method so that 'now' can be set for testing purposes
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setNow(Instant now)
|
||||||
|
{
|
||||||
|
this.now = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** makes request to check if a token is still valid and build new qSession if it is
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QSession revalidateToken(QInstance qInstance, String idToken) throws JwkException
|
||||||
|
{
|
||||||
|
Auth0AuthenticationMetaData metaData = (Auth0AuthenticationMetaData) qInstance.getAuthentication();
|
||||||
|
|
||||||
|
DecodedJWT jwt = JWT.decode(idToken);
|
||||||
|
JwkProvider provider = new UrlJwkProvider(metaData.getBaseUrl());
|
||||||
|
Jwk jwk = provider.get(jwt.getKeyId());
|
||||||
|
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
|
||||||
|
JWTVerifier verifier = JWT.require(algorithm)
|
||||||
|
.withIssuer(metaData.getBaseUrl())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
///////////////////////////////////
|
||||||
|
// make call to verify the token //
|
||||||
|
///////////////////////////////////
|
||||||
|
verifier.verify(idToken);
|
||||||
|
|
||||||
|
return (buildQSessionFromToken(idToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** extracts info from token creating a QSession
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QSession buildQSessionFromToken(String idToken) throws JwkException
|
||||||
|
{
|
||||||
|
////////////////////////////////////
|
||||||
|
// decode and extract the payload //
|
||||||
|
////////////////////////////////////
|
||||||
|
DecodedJWT jwt = JWT.decode(idToken);
|
||||||
|
Base64.Decoder decoder = Base64.getUrlDecoder();
|
||||||
|
String payloadString = new String(decoder.decode(jwt.getPayload()));
|
||||||
|
JSONObject payload = new JSONObject(payloadString);
|
||||||
|
|
||||||
|
QUser qUser = new QUser();
|
||||||
|
qUser.setIdReference(payload.getString("email"));
|
||||||
|
qUser.setFullName(payload.getString("name"));
|
||||||
|
|
||||||
|
QSession qSession = new QSession();
|
||||||
|
qSession.setIdReference(idToken);
|
||||||
|
qSession.setUser(qUser);
|
||||||
|
|
||||||
|
return (qSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Load an instance of the appropriate state provider
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static StateProviderInterface getStateProvider()
|
||||||
|
{
|
||||||
|
// TODO - read this from somewhere in meta data eh?
|
||||||
|
return (InMemoryStateProvider.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static class Auth0StateKey extends AbstractStateKey
|
||||||
|
{
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
Auth0StateKey(String key)
|
||||||
|
{
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return (this.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if(this == o)
|
||||||
|
return true;
|
||||||
|
if(o == null || getClass() != o.getClass())
|
||||||
|
return false;
|
||||||
|
Auth0StateKey that = (Auth0StateKey) o;
|
||||||
|
return key.equals(that.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return key.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,9 +24,9 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -40,7 +40,7 @@ public class FullyAnonymousAuthenticationModule implements QAuthenticationModule
|
|||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@Override
|
@Override
|
||||||
public QSession createSession(Map<String, String> context)
|
public QSession createSession(QInstance qInstance, Map<String, String> context)
|
||||||
{
|
{
|
||||||
QUser qUser = new QUser();
|
QUser qUser = new QUser();
|
||||||
qUser.setIdReference("anonymous");
|
qUser.setIdReference("anonymous");
|
||||||
@ -68,10 +68,6 @@ public class FullyAnonymousAuthenticationModule implements QAuthenticationModule
|
|||||||
@Override
|
@Override
|
||||||
public boolean isSessionValid(QSession session)
|
public boolean isSessionValid(QSession session)
|
||||||
{
|
{
|
||||||
if(session == null)
|
return session != null;
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
return (true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
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 org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -43,7 +44,7 @@ public class MockAuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@Override
|
@Override
|
||||||
public QSession createSession(Map<String, String> context)
|
public QSession createSession(QInstance qInstance, Map<String, String> context)
|
||||||
{
|
{
|
||||||
QUser qUser = new QUser();
|
QUser qUser = new QUser();
|
||||||
qUser.setIdReference("User:" + (System.currentTimeMillis() % USER_ID_MODULO));
|
qUser.setIdReference("User:" + (System.currentTimeMillis() % USER_ID_MODULO));
|
||||||
|
@ -25,8 +25,8 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -38,7 +38,7 @@ import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModu
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class QAuthenticationModuleDispatcher
|
public class QAuthenticationModuleDispatcher
|
||||||
{
|
{
|
||||||
private Map<String, String> authenticationTypeToModuleClassNameMap;
|
private final Map<String, String> authenticationTypeToModuleClassNameMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -48,9 +48,9 @@ public class QAuthenticationModuleDispatcher
|
|||||||
public QAuthenticationModuleDispatcher()
|
public QAuthenticationModuleDispatcher()
|
||||||
{
|
{
|
||||||
authenticationTypeToModuleClassNameMap = new HashMap<>();
|
authenticationTypeToModuleClassNameMap = new HashMap<>();
|
||||||
authenticationTypeToModuleClassNameMap.put("mock", "com.kingsrook.qqq.backend.core.modules.authentication.MockAuthenticationModule");
|
authenticationTypeToModuleClassNameMap.put(QAuthenticationType.MOCK.getName(), "com.kingsrook.qqq.backend.core.modules.authentication.MockAuthenticationModule");
|
||||||
authenticationTypeToModuleClassNameMap.put("fullyAnonymous", "com.kingsrook.qqq.backend.core.modules.authentication.FullyAnonymousAuthenticationModule");
|
authenticationTypeToModuleClassNameMap.put(QAuthenticationType.FULLY_ANONYMOUS.getName(), "com.kingsrook.qqq.backend.core.modules.authentication.FullyAnonymousAuthenticationModule");
|
||||||
authenticationTypeToModuleClassNameMap.put("TODO:google", "com.kingsrook.qqq.authentication.module.google.GoogleAuthenticationModule");
|
authenticationTypeToModuleClassNameMap.put(QAuthenticationType.AUTH_0.getName(), "com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule");
|
||||||
// todo - let user define custom type -> classes
|
// todo - let user define custom type -> classes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public class QAuthenticationModuleDispatcher
|
|||||||
throw (new QModuleDispatchException("No authentication meta data defined."));
|
throw (new QModuleDispatchException("No authentication meta data defined."));
|
||||||
}
|
}
|
||||||
|
|
||||||
return getQModule(authenticationMetaData.getType());
|
return getQModule(authenticationMetaData.getType().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +37,7 @@ public interface QAuthenticationModuleInterface
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
QSession createSession(Map<String, String> context);
|
QSession createSession(QInstance qInstance, Map<String, String> context) throws QAuthenticationException;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Meta-data to provide details of an RDBMS backend (e.g., connection params)
|
||||||
|
*******************************************************************************/
|
||||||
|
public class Auth0AuthenticationMetaData extends QAuthenticationMetaData
|
||||||
|
{
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Default Constructor.
|
||||||
|
*******************************************************************************/
|
||||||
|
public Auth0AuthenticationMetaData()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
setType(QAuthenticationType.AUTH_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter, override to help fluent flows
|
||||||
|
*******************************************************************************/
|
||||||
|
public Auth0AuthenticationMetaData withBaseUrl(String baseUrl)
|
||||||
|
{
|
||||||
|
setBaseUrl(baseUrl);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for baseUrl
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getBaseUrl()
|
||||||
|
{
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for baseUrl
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setBaseUrl(String baseUrl)
|
||||||
|
{
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,12 +19,13 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qqq.backend.core.model.metadata;
|
package com.kingsrook.qqq.backend.core.modules.authentication.metadata;
|
||||||
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.fasterxml.jackson.annotation.JsonFilter;
|
import com.fasterxml.jackson.annotation.JsonFilter;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -35,7 +36,7 @@ import com.fasterxml.jackson.annotation.JsonFilter;
|
|||||||
public class QAuthenticationMetaData
|
public class QAuthenticationMetaData
|
||||||
{
|
{
|
||||||
private String name;
|
private String name;
|
||||||
private String type;
|
private QAuthenticationType type;
|
||||||
|
|
||||||
@JsonFilter("secretsFilter")
|
@JsonFilter("secretsFilter")
|
||||||
private Map<String, String> values;
|
private Map<String, String> values;
|
||||||
@ -120,7 +121,7 @@ public class QAuthenticationMetaData
|
|||||||
** Getter for type
|
** Getter for type
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public String getType()
|
public QAuthenticationType getType()
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -131,7 +132,7 @@ public class QAuthenticationMetaData
|
|||||||
** Setter for type
|
** Setter for type
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void setType(String type)
|
public void setType(QAuthenticationType type)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
@ -141,7 +142,7 @@ public class QAuthenticationMetaData
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public QAuthenticationMetaData withType(String type)
|
public QAuthenticationMetaData withType(QAuthenticationType type)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
return (this);
|
return (this);
|
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.Auth0AuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule.AUTH0_ID_TOKEN_KEY;
|
||||||
|
import static com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule.COULD_NOT_DECODE_ERROR;
|
||||||
|
import static com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule.EXPIRED_TOKEN_ERROR;
|
||||||
|
import static com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule.INVALID_TOKEN_ERROR;
|
||||||
|
import static com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule.TOKEN_NOT_PROVIDED_ERROR;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for the FullyAnonymousAuthenticationModule
|
||||||
|
*******************************************************************************/
|
||||||
|
public class Auth0AuthenticationModuleTest
|
||||||
|
{
|
||||||
|
private static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IllrY2FkWTA0Q3RFVUFxQUdLNTk3ayJ9.eyJnaXZlbl9uYW1lIjoiVGltIiwiZmFtaWx5X25hbWUiOiJDaGFtYmVybGFpbiIsIm5pY2tuYW1lIjoidGltLmNoYW1iZXJsYWluIiwibmFtZSI6IlRpbSBDaGFtYmVybGFpbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQUZkWnVjcXVSaUFvTzk1RG9URklnbUtseVA1akVBVnZmWXFnS0lHTkVubzE9czk2LWMiLCJsb2NhbGUiOiJlbiIsInVwZGF0ZWRfYXQiOiIyMDIyLTA3LTE5VDE2OjI0OjQ1LjgyMloiLCJlbWFpbCI6InRpbS5jaGFtYmVybGFpbkBraW5nc3Jvb2suY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8va2luZ3Nyb29rLnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwODk2NDEyNjE3MjY1NzAzNDg2NyIsImF1ZCI6InNwQ1NtczAzcHpVZGRYN1BocHN4ZDlUd2FLMDlZZmNxIiwiaWF0IjoxNjU4MjQ3OTAyLCJleHAiOjE2NTgyODM5MDIsIm5vbmNlIjoiZUhOdFMxbEtUR2N5ZG5KS1VVY3RkRTFVT0ZKNmJFNUxVVkEwZEdsRGVXOXZkVkl4UW41eVRrUlJlZz09In0.hib7JR8NDU2kx8Fj1bnzo3IUuabE6Hb-Z7HHZAJPQuF_Zdg3L1KDypn6SY7HAd_dsz2N8RkXfvQto-Y2g2ukuz7FxzNFgcVL99cyEO3YqmyCa6JTOTCrxdeaIE8QZpCEKvC28oeJBv0wO1Dwc--OVJMsK2vSzyxj1WNok64YYjWKLL4c0dFf-nj0KWFr1IU-tMiyWLDDiJw2Sa8M4YxXZYqdlkgNmrBPExgcm9l9SiT2l3Ts3Sgc_IyMVyMrnV8XX50EWdsm6vuCOSUcqf0XhjDQ7urZveoVwVLnYq3GcLhVBcy1Hr9RL8zPdPynOzsbX6uCww2Esrv6iwWrgQ5zBA";
|
||||||
|
private static final String INVALID_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IllrY2FkWTA0Q3RFVUFxQUdLNTk3ayJ9.eyJnaXZlbl9uYW1lIjoiVGltIiwiZmFtaWx5X25hbWUiOiJDaGFtYmVybGFpbiIsIm5pY2tuYW1lIjoidGltLmNoYW1iZXJsYWluIiwibmFtZSI6IlRpbSBDaGFtYmVybGFpbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQUZkWnVjcXVSaUFvTzk1RG9URklnbUtseVA1akVBVnZmWXFnS0lHTkVubzE9czk2LWMiLCJsb2NhbGUiOiJlbiIsInVwZGF0ZWRfYXQiOiIyMDIyLTA3LTE5VDE2OjI0OjQ1LjgyMloiLCJlbWFpbCI6InRpbS5jaGFtYmVybGFpbkBraW5nc3Jvb2suY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8va2luZ3Nyb29rLnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwODk2NDEyNjE3MjY1NzAzNDg2NyIsImF1ZCI6InNwQ1NtczAzcHpVZGRYN1BocHN4ZDlUd2FLMDlZZmNxIiwiaWF0IjoxNjU4MjQ3OTAyLCJleHAiOjE2NTgyODM5MDIsIm5vbmNlIjoiZUhOdFMxbEtUR2N5ZG5KS1VVY3RkRTFVT0ZKNmJFNUxVVkEwZEdsRGVXOXZkVkl4UW41eVRrUlJlZz09In0.hib7JR8NDU2kx8Fj1bnzo3IUuabE6Hb-Z7HHZAJPQuF_Zdg3L1KDypn6SY7HAd_dsz2N8RkXfvQto-Y2g2ukuz7FxzNFgcVL99cyEO3YqmyCa6JTOTCrxdeaIE8QZpCEKvC28oeJBv0wO1Dwc--OVJMsK2vSzyxj1WNok64YYjWKLL4c0dFf-nj0KWFr1IU-tMiyWLDDiJw2Sa8M4YxXZYqdlkgNmrBPExgcm9l9SiT2l3Ts3Sgc_IyMVyMrnV8XX50EWdsm6vuCOSUcqf0XhjDQ7urZveoVwVLnYq3GcLhVBcy1Hr9RL8zPdPynOzsbX6uCww2Esrv6iwWrgQ5zBA-thismakesinvalid";
|
||||||
|
private static final String EXPIRED_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IllrY2FkWTA0Q3RFVUFxQUdLNTk3ayJ9.eyJnaXZlbl9uYW1lIjoiVGltIiwiZmFtaWx5X25hbWUiOiJDaGFtYmVybGFpbiIsIm5pY2tuYW1lIjoidGltLmNoYW1iZXJsYWluIiwibmFtZSI6IlRpbSBDaGFtYmVybGFpbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQUZkWnVjcXVSaUFvTzk1RG9URklnbUtseVA1akVBVnZmWXFnS0lHTkVubzE9czk2LWMiLCJsb2NhbGUiOiJlbiIsInVwZGF0ZWRfYXQiOiIyMDIyLTA3LTE4VDIxOjM4OjE1LjM4NloiLCJlbWFpbCI6InRpbS5jaGFtYmVybGFpbkBraW5nc3Jvb2suY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8va2luZ3Nyb29rLnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwODk2NDEyNjE3MjY1NzAzNDg2NyIsImF1ZCI6InNwQ1NtczAzcHpVZGRYN1BocHN4ZDlUd2FLMDlZZmNxIiwiaWF0IjoxNjU4MTgwNDc3LCJleHAiOjE2NTgyMTY0NzcsIm5vbmNlIjoiVkZkQlYzWmplR2hvY1cwMk9WZEtabHBLU0c1K1ZXbElhMEV3VkZaeFpVdEJVMDErZUZaT1RtMTNiZz09In0.fU7EwUgNrupOPz_PX_aQKON2xG1-LWD85xVo1Bn41WNEek-iMyJoch8l6NUihi7Bou14BoOfeWIG_sMqsLHqI2Pk7el7l1kigsjURx0wpiXadBt8piMxdIlxdToZEMuZCBzg7eJvXh4sM8tlV5cm0gPa6FT9Ih3VGJajNlXi5BcYS_JRpIvFvHn8-Bxj4KiAlZ5XPPkopjnDgP8kFfc4cMn_nxDkqWYlhj-5TaGW2xCLC9Qr_9UNxX0fm-CkKjYs3Z5ezbiXNkc-bxrCYvxeBeDPf8-T3EqrxCRVqCZSJ85BHdOc_E7UZC_g8bNj0umoplGwlCbzO4XIuOO-KlIaOg";
|
||||||
|
private static final String UNDECODABLE_TOKEN = "UNDECODABLE";
|
||||||
|
|
||||||
|
public static final String AUTH0_BASE_URL = "https://kingsrook.us.auth0.com/";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test a valid token where 'now' is set to a time that would be valid for it
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testValidToken() throws QAuthenticationException
|
||||||
|
{
|
||||||
|
Map<String, String> context = new HashMap<>();
|
||||||
|
context.put(AUTH0_ID_TOKEN_KEY, VALID_TOKEN);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Tuesday, July 19, 2022 12:40:27.299 PM GMT-05:00 DST //
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
Instant now = Instant.ofEpochMilli(1658252427299L);
|
||||||
|
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.setNow(now);
|
||||||
|
QSession session = auth0AuthenticationModule.createSession(getQInstance(), context);
|
||||||
|
assertTrue(session.getUser().getIdReference().equals("tim.chamberlain@kingsrook.com"));
|
||||||
|
assertTrue(session.getUser().getFullName().equals("Tim Chamberlain"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test failure case, token is invalid
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testInvalidToken()
|
||||||
|
{
|
||||||
|
Map<String, String> context = new HashMap<>();
|
||||||
|
context.put(AUTH0_ID_TOKEN_KEY, INVALID_TOKEN);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.createSession(getQInstance(), context);
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
assertTrue(qae.getMessage().contains(INVALID_TOKEN_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Should never get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test failure case, token cant be decoded
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testUndecodableToken()
|
||||||
|
{
|
||||||
|
Map<String, String> context = new HashMap<>();
|
||||||
|
context.put(AUTH0_ID_TOKEN_KEY, UNDECODABLE_TOKEN);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.createSession(getQInstance(), context);
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
assertTrue(qae.getMessage().contains(COULD_NOT_DECODE_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Should never get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test failure case, token is expired
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testProperlyFormattedButExpiredToken()
|
||||||
|
{
|
||||||
|
Map<String, String> context = new HashMap<>();
|
||||||
|
context.put(AUTH0_ID_TOKEN_KEY, EXPIRED_TOKEN);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.createSession(getQInstance(), context);
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
assertTrue(qae.getMessage().contains(EXPIRED_TOKEN_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Should never get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test failure case, empty context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testEmptyContext()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.createSession(getQInstance(), new HashMap<>());
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
assertTrue(qae.getMessage().contains(TOKEN_NOT_PROVIDED_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Should never get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test failure case, null token
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testNullToken()
|
||||||
|
{
|
||||||
|
Map<String, String> context = new HashMap<>();
|
||||||
|
context.put(AUTH0_ID_TOKEN_KEY, null);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Auth0AuthenticationModule auth0AuthenticationModule = new Auth0AuthenticationModule();
|
||||||
|
auth0AuthenticationModule.createSession(getQInstance(), context);
|
||||||
|
}
|
||||||
|
catch(QAuthenticationException qae)
|
||||||
|
{
|
||||||
|
assertTrue(qae.getMessage().contains(TOKEN_NOT_PROVIDED_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Should never get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** utility method to prime a qInstance for auth0 tests
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QInstance getQInstance()
|
||||||
|
{
|
||||||
|
QAuthenticationMetaData authenticationMetaData = new Auth0AuthenticationMetaData()
|
||||||
|
.withBaseUrl(AUTH0_BASE_URL)
|
||||||
|
.withName("auth0");
|
||||||
|
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
qInstance.setAuthentication(authenticationMetaData);
|
||||||
|
return (qInstance);
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,6 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.FullyAnonymousAuthenticationModule;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
@ -36,12 +35,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
public class FullyAnonymousAuthenticationModuleTest
|
public class FullyAnonymousAuthenticationModuleTest
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
@Test
|
@Test
|
||||||
public void test()
|
public void test()
|
||||||
{
|
{
|
||||||
FullyAnonymousAuthenticationModule fullyAnonymousAuthenticationModule = new FullyAnonymousAuthenticationModule();
|
FullyAnonymousAuthenticationModule fullyAnonymousAuthenticationModule = new FullyAnonymousAuthenticationModule();
|
||||||
|
|
||||||
QSession session = fullyAnonymousAuthenticationModule.createSession(null);
|
QSession session = fullyAnonymousAuthenticationModule.createSession(null, null);
|
||||||
|
|
||||||
assertNotNull(session, "Session should not be null");
|
assertNotNull(session, "Session should not be null");
|
||||||
assertNotNull(session.getIdReference(), "Session id ref should not be null");
|
assertNotNull(session.getIdReference(), "Session id ref should not be null");
|
||||||
@ -51,4 +53,4 @@ public class FullyAnonymousAuthenticationModuleTest
|
|||||||
assertFalse(fullyAnonymousAuthenticationModule.isSessionValid(null), "null should be not valid");
|
assertFalse(fullyAnonymousAuthenticationModule.isSessionValid(null), "null should be not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,7 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
|
|||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
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.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
@ -26,8 +26,9 @@ import java.util.List;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.AddAge;
|
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.AddAge;
|
||||||
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.GetAgeStatistics;
|
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.GetAgeStatistics;
|
||||||
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
|
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||||
@ -109,7 +110,7 @@ public class TestUtils
|
|||||||
{
|
{
|
||||||
return new QAuthenticationMetaData()
|
return new QAuthenticationMetaData()
|
||||||
.withName("mock")
|
.withName("mock")
|
||||||
.withType("mock");
|
.withType(QAuthenticationType.MOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -304,6 +305,6 @@ public class TestUtils
|
|||||||
public static QSession getMockSession()
|
public static QSession getMockSession()
|
||||||
{
|
{
|
||||||
MockAuthenticationModule mockAuthenticationModule = new MockAuthenticationModule();
|
MockAuthenticationModule mockAuthenticationModule = new MockAuthenticationModule();
|
||||||
return (mockAuthenticationModule.createSession(null));
|
return (mockAuthenticationModule.createSession(null, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user