CE-1068 - Add creating an automated-session for a user, to use those security keys while running a report

This commit is contained in:
2024-05-01 16:46:59 -05:00
parent b3fb15e550
commit e853c67b67
6 changed files with 158 additions and 3 deletions

View File

@ -42,7 +42,7 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableMap;
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public class QSession implements Serializable public class QSession implements Serializable, Cloneable
{ {
private String idReference; private String idReference;
private QUser user; private QUser user;
@ -68,6 +68,58 @@ public class QSession implements Serializable
/*******************************************************************************
**
*******************************************************************************/
@Override
public QSession clone() throws CloneNotSupportedException
{
QSession clone = (QSession) super.clone();
if(user != null)
{
clone.user = user.clone();
}
if(permissions != null)
{
clone.permissions = new HashSet<>();
clone.permissions.addAll(permissions);
}
if(securityKeyValues != null)
{
clone.securityKeyValues = new HashMap<>();
for(Map.Entry<String, List<Serializable>> entry : securityKeyValues.entrySet())
{
List<Serializable> cloneValues = entry.getValue() == null ? null : new ArrayList<>(entry.getValue());
clone.securityKeyValues.put(entry.getKey(), cloneValues);
}
}
if(backendVariants != null)
{
clone.backendVariants = new HashMap<>();
clone.backendVariants.putAll(backendVariants);
}
if(values != null)
{
clone.values = new HashMap<>();
clone.values.putAll(values);
}
if(valuesForFrontend != null)
{
clone.valuesForFrontend = new HashMap<>();
clone.valuesForFrontend.putAll(valuesForFrontend);
}
return (clone);
}
/******************************************************************************* /*******************************************************************************
** Default constructor, puts a uuid in the session ** Default constructor, puts a uuid in the session
** **

View File

@ -25,13 +25,24 @@ package com.kingsrook.qqq.backend.core.model.session;
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public class QUser public class QUser implements Cloneable
{ {
private String idReference; private String idReference;
private String fullName; private String fullName;
/*******************************************************************************
**
*******************************************************************************/
@Override
public QUser clone() throws CloneNotSupportedException
{
return (QUser) super.clone();
}
/******************************************************************************* /*******************************************************************************
** Getter for idReference ** Getter for idReference
** **

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.modules.authentication;
import java.io.Serializable; import java.io.Serializable;
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.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
@ -62,4 +63,14 @@ public interface QAuthenticationModuleCustomizerInterface
////////// //////////
} }
/*******************************************************************************
**
*******************************************************************************/
default void customizeAutomatedSessionForUser(QInstance qInstance, QSession automatedSessionForUser, Serializable userId) throws QAuthenticationException
{
//////////
// noop //
//////////
}
} }

View File

@ -22,12 +22,15 @@
package com.kingsrook.qqq.backend.core.modules.authentication; package com.kingsrook.qqq.backend.core.modules.authentication;
import java.io.Serializable;
import java.util.Map; import java.util.Map;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.AccessTokenException; import com.kingsrook.qqq.backend.core.exceptions.AccessTokenException;
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException; import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData; import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.NotImplementedException;
@ -49,6 +52,27 @@ public interface QAuthenticationModuleInterface
boolean isSessionValid(QInstance instance, QSession session); boolean isSessionValid(QInstance instance, QSession session);
/*******************************************************************************
**
*******************************************************************************/
default QSession createAutomatedSessionForUser(QInstance qInstance, Serializable userId) throws QAuthenticationException
{
try
{
QSession clone = QContext.getQSession().clone();
if(clone.getUser() != null)
{
clone.getUser().setIdReference(ValueUtils.getValueAsString(userId));
}
return clone;
}
catch(CloneNotSupportedException e)
{
throw (new QAuthenticationException("Cloning session failed", e));
}
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.backend.core.modules.authentication.implementations; package com.kingsrook.qqq.backend.core.modules.authentication.implementations;
import java.io.Serializable;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPublicKey;
import java.time.Duration; import java.time.Duration;
@ -1108,4 +1109,20 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
return (null); return (null);
} }
} }
/*******************************************************************************
** e.g., if a scheduled job needs to run as a user (say, a report)...
*******************************************************************************/
@Override
public QSession createAutomatedSessionForUser(QInstance qInstance, Serializable userId) throws QAuthenticationException
{
QSession automatedSessionForUser = QAuthenticationModuleInterface.super.createAutomatedSessionForUser(qInstance, userId);
if(getCustomizer() != null)
{
getCustomizer().customizeAutomatedSessionForUser(qInstance, automatedSessionForUser, userId);
}
return (automatedSessionForUser);
}
} }

View File

@ -26,6 +26,7 @@ import java.util.List;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory; import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory;
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
@ -34,7 +35,11 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutp
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
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.savedreports.ScheduledReport; import com.kingsrook.qqq.backend.core.model.savedreports.ScheduledReport;
import com.kingsrook.qqq.backend.core.model.session.QSession;
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.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;
@ -69,6 +74,11 @@ public class RunScheduledReportExecuteStep implements BackendStep
ScheduledReport scheduledReport = new ScheduledReport(records.get(0)); ScheduledReport scheduledReport = new ScheduledReport(records.get(0));
scheduledReportId = scheduledReport.getId(); scheduledReportId = scheduledReport.getId();
////////////////////////////////////////////////////////////////////////////////////
// get the schedule's user - as that will drive the security key we need to apply //
////////////////////////////////////////////////////////////////////////////////////
updateSessionForUser(scheduledReport.getUserId());
///////////////////////////////////////////// /////////////////////////////////////////////
// run the process that renders the report // // run the process that renders the report //
///////////////////////////////////////////// /////////////////////////////////////////////
@ -110,4 +120,34 @@ public class RunScheduledReportExecuteStep implements BackendStep
} }
} }
/*******************************************************************************
**
*******************************************************************************/
private void updateSessionForUser(String userId) throws QException
{
try
{
QInstance qInstance = QContext.getQInstance();
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication());
///////////////////////////////////////
// create automated-session for user //
///////////////////////////////////////
QSession session = authenticationModule.createAutomatedSessionForUser(qInstance, userId);
/////////////////////////////////////////////
// set that session in the current context //
/////////////////////////////////////////////
QContext.setQSession(session);
}
catch(Exception e)
{
LOG.warn("Error setting up user session for running scheduled report", e, logPair("userId", userId));
throw (new QException("Error setting up user session for running scheduled report", e));
}
}
} }