package org.zaproxy.zap.authentication; import java.awt.BorderLayout; import java.awt.Component; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.script.ScriptException; import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.plaf.basic.BasicComboBoxRenderer; import net.sf.json.JSONObject; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.control.Control; import org.parosproxy.paros.db.DatabaseException; import org.parosproxy.paros.db.RecordContext; import org.parosproxy.paros.extension.ExtensionHook; import org.parosproxy.paros.model.Model; import org.parosproxy.paros.model.Session; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.network.HttpSender; import org.parosproxy.paros.view.View; import org.zaproxy.zap.ZAP; import org.zaproxy.zap.authentication.GenericAuthenticationCredentials.GenericAuthenticationCredentialsOptionsPanel; import org.zaproxy.zap.extension.api.ApiDynamicActionImplementor; import org.zaproxy.zap.extension.api.ApiException; import org.zaproxy.zap.extension.api.ApiResponse; import org.zaproxy.zap.extension.api.ApiResponseSet; import org.zaproxy.zap.extension.authentication.AuthenticationAPI; import org.zaproxy.zap.extension.script.ExtensionScript; import org.zaproxy.zap.extension.script.ScriptType; import org.zaproxy.zap.extension.script.ScriptWrapper; import org.zaproxy.zap.model.Context; import org.zaproxy.zap.session.SessionManagementMethod; import org.zaproxy.zap.session.WebSession; import org.zaproxy.zap.users.User; import org.zaproxy.zap.utils.ApiUtils; import org.zaproxy.zap.utils.EncodingUtils; import org.zaproxy.zap.view.DynamicFieldsPanel; import org.zaproxy.zap.view.LayoutHelper; public class ScriptBasedAuthenticationMethodType extends AuthenticationMethodType { public static final String CONTEXT_CONFIG_AUTH_SCRIPT = AuthenticationMethod.CONTEXT_CONFIG_AUTH + ".script"; public static final String CONTEXT_CONFIG_AUTH_SCRIPT_NAME = CONTEXT_CONFIG_AUTH_SCRIPT + ".name"; public static final String CONTEXT_CONFIG_AUTH_SCRIPT_PARAMS = CONTEXT_CONFIG_AUTH_SCRIPT + ".params"; public static final int METHOD_IDENTIFIER = 4; private static final Logger log = Logger.getLogger(ScriptBasedAuthenticationMethodType.class); /** The Constant SCRIPT_TYPE_AUTH. */ public static final String SCRIPT_TYPE_AUTH = "authentication"; private static final String API_METHOD_NAME = "scriptBasedAuthentication"; /** The SCRIPT ICON. */ private static final ImageIcon SCRIPT_ICON_AUTH = new ImageIcon( ZAP.class.getResource("/resource/icon/16/script-auth.png")); /** The Authentication method's name. */ private static final String METHOD_NAME = Constant.messages.getString("authentication.method.script.name"); private ExtensionScript extensionScript; public class ScriptBasedAuthenticationMethod extends AuthenticationMethod { private ScriptWrapper script; private String[] credentialsParamNames; private Map<String, String> paramValues; private HttpSender httpSender; protected HttpSender getHttpSender() { if (this.httpSender == null) { this.httpSender = new HttpSender(Model.getSingleton().getOptionsParam().getConnectionParam(), true, HttpSender.AUTHENTICATION_INITIATOR); } return httpSender; } /** * Load a script and fills in the method's filled according to the values specified by the * script. * <p> * If the method already had a loaded script and a set of values for the parameters, it * tries to provide new values for the new parameters if they match any previous parameter * names. * * @param scriptW the script wrapper * @throws IllegalArgumentException if an error occurs while loading the script. */ public void loadScript(ScriptWrapper scriptW) { AuthenticationScript script = getScriptInterfaceV2(scriptW); if (script == null) { script = getScriptInterface(scriptW); } if (script == null) { log.warn("The script " + scriptW.getName() + " does not properly implement the Authentication Script interface."); throw new IllegalArgumentException(Constant.messages.getString( "authentication.method.script.dialog.error.text.interface", scriptW.getName())); } try { if (script instanceof AuthenticationScriptV2) { AuthenticationScriptV2 scriptV2 = (AuthenticationScriptV2) script; setLoggedInIndicatorPattern(scriptV2.getLoggedInIndicator()); setLoggedOutIndicatorPattern(scriptV2.getLoggedOutIndicator()); } String[] requiredParams = script.getRequiredParamsNames(); String[] optionalParams = script.getOptionalParamsNames(); this.credentialsParamNames = script.getCredentialsParamsNames(); if (log.isDebugEnabled()) { log.debug("Loaded authentication script - required parameters: " + Arrays.toString(requiredParams) + " - optional parameters: " + Arrays.toString(optionalParams)); } // If there's an already loaded script, make sure we save its values and _try_ // to use them Map<String, String> oldValues = this.paramValues != null ? this.paramValues : Collections .<String, String> emptyMap(); this.paramValues = new HashMap<>(requiredParams.length + optionalParams.length); for (String param : requiredParams) this.paramValues.put(param, oldValues.get(param)); for (String param : optionalParams) this.paramValues.put(param, oldValues.get(param)); this.script = scriptW; log.info("Successfully loaded new script for ScriptBasedAuthentication: " + this); } catch (Exception e) { log.error("Error while loading authentication script", e); getScriptsExtension().handleScriptException(this.script, e); throw new IllegalArgumentException(Constant.messages.getString( "authentication.method.script.dialog.error.text.loading", e.getMessage())); } } @Override public String toString() { return "ScriptBasedAuthenticationMethod [script=" + script + ", paramValues=" + paramValues + ", credentialsParamNames=" + Arrays.toString(credentialsParamNames) + "]"; } @Override public boolean isConfigured() { return true; } @Override protected AuthenticationMethod duplicate() { ScriptBasedAuthenticationMethod method = new ScriptBasedAuthenticationMethod(); method.script = script; method.paramValues = this.paramValues != null ? new HashMap<String, String>(this.paramValues) : null; method.credentialsParamNames = this.credentialsParamNames; return method; } @Override public boolean validateCreationOfAuthenticationCredentials() { if (credentialsParamNames != null) { return true; } if (View.isInitialised()) { View.getSingleton().showMessageDialog( Constant.messages.getString("authentication.method.script.dialog.error.text.notLoaded")); } return false; } @Override public AuthenticationCredentials createAuthenticationCredentials() { return new GenericAuthenticationCredentials(this.credentialsParamNames); } @Override public AuthenticationMethodType getType() { return new ScriptBasedAuthenticationMethodType(); } @Override public WebSession authenticate(SessionManagementMethod sessionManagementMethod, AuthenticationCredentials credentials, User user) throws UnsupportedAuthenticationCredentialsException { // type check if (!(credentials instanceof GenericAuthenticationCredentials)) { throw new UnsupportedAuthenticationCredentialsException( "Script based Authentication method only supports " + GenericAuthenticationCredentials.class.getSimpleName() + ". Received: " + credentials.getClass()); } GenericAuthenticationCredentials cred = (GenericAuthenticationCredentials) credentials; // Call the script to get an authenticated message from which we can then extract the // session AuthenticationScript script = getScriptInterfaceV2(this.script); if (script == null) { script = getScriptInterface(this.script); } if (script == null) { return null; } HttpMessage msg = null; try { if (script instanceof AuthenticationScriptV2) { AuthenticationScriptV2 scriptV2 = (AuthenticationScriptV2) script; setLoggedInIndicatorPattern(scriptV2.getLoggedInIndicator()); setLoggedOutIndicatorPattern(scriptV2.getLoggedOutIndicator()); } msg = script.authenticate(new AuthenticationHelper(getHttpSender(), sessionManagementMethod, user), this.paramValues, cred); } catch (Exception e) { // Catch Exception instead of ScriptException and IOException because script engine implementations // might throw other exceptions on script errors (e.g. jdk.nashorn.internal.runtime.ECMAException) log.error("An error occurred while trying to authenticate using the Authentication Script: " + this.script.getName(), e); getScriptsExtension().handleScriptException(this.script, e); return null; } if (this.isAuthenticated(msg)) { // Let the user know it worked AuthenticationHelper.notifyOutputAuthSuccessful(msg); } else { // Let the user know it failed AuthenticationHelper.notifyOutputAuthFailure(msg); } // Add message to history AuthenticationHelper.addAuthMessageToHistory(msg); // Return the web session as extracted by the session management method return sessionManagementMethod.extractWebSession(msg); } @Override public ApiResponse getApiResponseRepresentation() { Map<String, String> values = new HashMap<>(); values.put("methodName", API_METHOD_NAME); values.put("scriptName", script.getName()); values.putAll(paramValues); return new ApiResponseSet<String>("method", values); } } public class ScriptBasedAuthenticationMethodOptionsPanel extends AbstractAuthenticationMethodOptionsPanel { private static final long serialVersionUID = 7812841049435409987L; private final String SCRIPT_NAME_LABEL = Constant.messages .getString("authentication.method.script.field.label.scriptName"); private final String LABEL_NOT_LOADED = Constant.messages .getString("authentication.method.script.field.label.notLoaded"); private JComboBox<ScriptWrapper> scriptsComboBox; private JButton loadScriptButton; private ScriptBasedAuthenticationMethod method; private AuthenticationIndicatorsPanel indicatorsPanel; private ScriptWrapper loadedScript; private JPanel dynamicContentPanel; private DynamicFieldsPanel dynamicFieldsPanel; private String[] loadedCredentialParams; public ScriptBasedAuthenticationMethodOptionsPanel() { super(); initialize(); } @SuppressWarnings("unchecked") private void initialize() { this.setLayout(new GridBagLayout()); this.add(new JLabel(SCRIPT_NAME_LABEL), LayoutHelper.getGBC(0, 0, 1, 0.0d, 0.0d)); this.scriptsComboBox = new JComboBox<>(); this.scriptsComboBox.setRenderer(new ScriptWrapperRenderer(this)); this.add(this.scriptsComboBox, LayoutHelper.getGBC(1, 0, 1, 1.0d, 0.0d)); this.loadScriptButton = new JButton("Load"); this.add(this.loadScriptButton, LayoutHelper.getGBC(2, 0, 1, 0.0d, 0.0d)); this.loadScriptButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { loadScript((ScriptWrapper) scriptsComboBox.getSelectedItem(), true); } }); // Make sure the 'Load' button is disabled when nothing is selected this.loadScriptButton.setEnabled(false); this.scriptsComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { loadScriptButton.setEnabled(scriptsComboBox.getSelectedIndex() >= 0); } }); this.dynamicContentPanel = new JPanel(new BorderLayout()); this.add(this.dynamicContentPanel, LayoutHelper.getGBC(0, 1, 3, 1.0d, 0.0d)); this.dynamicContentPanel.add(new JLabel(LABEL_NOT_LOADED)); } @Override public void validateFields() throws IllegalStateException { if (this.loadedScript == null) { this.scriptsComboBox.requestFocusInWindow(); throw new IllegalStateException( Constant.messages .getString("authentication.method.script.dialog.error.text.notLoadedNorConfigured")); } this.dynamicFieldsPanel.validateFields(); } @Override public void saveMethod() { this.method.script = (ScriptWrapper) this.scriptsComboBox.getSelectedItem(); // This method will also be called when switching panels to save a temporary state so // the state of the authentication method might not be valid if (this.dynamicFieldsPanel != null) this.method.paramValues = this.dynamicFieldsPanel.getFieldValues(); else this.method.paramValues = Collections.emptyMap(); if (this.loadedScript != null) this.method.credentialsParamNames = this.loadedCredentialParams; } @Override public void bindMethod(AuthenticationMethod method) throws UnsupportedAuthenticationMethodException { this.method = (ScriptBasedAuthenticationMethod) method; // Make sure the list of scripts is refreshed List<ScriptWrapper> scripts = getScriptsExtension().getScripts(SCRIPT_TYPE_AUTH); DefaultComboBoxModel<ScriptWrapper> model = new DefaultComboBoxModel<>( scripts.toArray(new ScriptWrapper[scripts.size()])); this.scriptsComboBox.setModel(model); this.scriptsComboBox.setSelectedItem(this.method.script); this.loadScriptButton.setEnabled(this.method.script != null); // Load the selected script, if any if (this.method.script != null) { loadScript(this.method.script, false); if (this.dynamicFieldsPanel != null) this.dynamicFieldsPanel.bindFieldValues(this.method.paramValues); } } @Override public void bindMethod(AuthenticationMethod method, AuthenticationIndicatorsPanel indicatorsPanel) throws UnsupportedAuthenticationMethodException { this.indicatorsPanel = indicatorsPanel; bindMethod(method); } @Override public AuthenticationMethod getMethod() { return this.method; } private void loadScript(ScriptWrapper scriptW, boolean adaptOldValues) { AuthenticationScript script = getScriptInterfaceV2(scriptW); if (script == null) { script = getScriptInterface(scriptW); } if (script == null) { log.warn("The script " + scriptW.getName() + " does not properly implement the Authentication Script interface."); warnAndResetPanel(Constant.messages.getString( "authentication.method.script.dialog.error.text.interface", scriptW.getName())); return; } try { if (script instanceof AuthenticationScriptV2) { AuthenticationScriptV2 scriptV2 = (AuthenticationScriptV2) script; String toolTip = Constant.messages .getString("authentication.method.script.dialog.loggedInOutIndicatorsInScript.toolTip"); String loggedInIndicator = scriptV2.getLoggedInIndicator(); this.method.setLoggedInIndicatorPattern(loggedInIndicator); this.indicatorsPanel.setLoggedInIndicatorPattern(loggedInIndicator); this.indicatorsPanel.setLoggedInIndicatorEnabled(false); this.indicatorsPanel.setLoggedInIndicatorToolTip(toolTip); String loggedOutIndicator = scriptV2.getLoggedOutIndicator(); this.method.setLoggedOutIndicatorPattern(loggedOutIndicator); this.indicatorsPanel.setLoggedOutIndicatorPattern(loggedOutIndicator); this.indicatorsPanel.setLoggedOutIndicatorEnabled(false); this.indicatorsPanel.setLoggedOutIndicatorToolTip(toolTip); } else { this.indicatorsPanel.setLoggedInIndicatorEnabled(true); this.indicatorsPanel.setLoggedInIndicatorToolTip(null); this.indicatorsPanel.setLoggedOutIndicatorEnabled(true); this.indicatorsPanel.setLoggedOutIndicatorToolTip(null); } String[] requiredParams = script.getRequiredParamsNames(); String[] optionalParams = script.getOptionalParamsNames(); this.loadedCredentialParams = script.getCredentialsParamsNames(); if (log.isDebugEnabled()) { log.debug("Loaded authentication script - required parameters: " + Arrays.toString(requiredParams) + " - optional parameters: " + Arrays.toString(optionalParams)); } // If there's an already loaded script, make sure we save its values and _try_ // to place them in the new panel Map<String, String> oldValues = null; if (adaptOldValues && dynamicFieldsPanel != null) { oldValues = dynamicFieldsPanel.getFieldValues(); if (log.isDebugEnabled()) log.debug("Trying to adapt old values: " + oldValues); } this.dynamicFieldsPanel = new DynamicFieldsPanel(requiredParams, optionalParams); this.loadedScript = scriptW; if (adaptOldValues && oldValues != null) this.dynamicFieldsPanel.bindFieldValues(oldValues); this.dynamicContentPanel.removeAll(); this.dynamicContentPanel.add(dynamicFieldsPanel, BorderLayout.CENTER); this.dynamicContentPanel.revalidate(); } catch (Exception e) { getScriptsExtension().handleScriptException(scriptW, e); log.error("Error while calling authentication script", e); warnAndResetPanel(Constant.messages.getString( "authentication.method.script.dialog.error.text.loading", e.getMessage())); } } private void warnAndResetPanel(String errorMessage) { JOptionPane.showMessageDialog(this, errorMessage, Constant.messages.getString("authentication.method.script.dialog.error.title"), JOptionPane.ERROR_MESSAGE); this.loadedScript = null; this.scriptsComboBox.setSelectedItem(null); this.dynamicFieldsPanel = null; this.dynamicContentPanel.removeAll(); this.dynamicContentPanel.add(new JLabel(LABEL_NOT_LOADED), BorderLayout.CENTER); this.dynamicContentPanel.revalidate(); } } /** * A renderer for properly displaying the name of a {@link ScriptWrapper} in a ComboBox and * putting emphasis on loaded script. */ private static class ScriptWrapperRenderer extends BasicComboBoxRenderer { private static final long serialVersionUID = 3654541772447187317L; private static final Border BORDER = new EmptyBorder(2, 3, 3, 3); private ScriptBasedAuthenticationMethodOptionsPanel panel; public ScriptWrapperRenderer(ScriptBasedAuthenticationMethodOptionsPanel panel) { super(); this.panel = panel; } @Override @SuppressWarnings("rawtypes") public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null) { setBorder(BORDER); ScriptWrapper item = (ScriptWrapper) value; if (panel.loadedScript == item) setText("<html><b>" + item.getName() + " (loaded)</b></html>"); else setText(item.getName()); } return this; } } @Override public void hook(ExtensionHook extensionHook) { // Hook up the Script Type if (getScriptsExtension() != null) { log.debug("Registering Script..."); getScriptsExtension().registerScriptType( new ScriptType(SCRIPT_TYPE_AUTH, "authentication.method.script.type", SCRIPT_ICON_AUTH, false, new String[] {ScriptType.CAPABILITY_APPEND})); } } @Override public ScriptBasedAuthenticationMethod createAuthenticationMethod(int contextId) { return new ScriptBasedAuthenticationMethod(); } @Override public String getName() { return METHOD_NAME; } @Override public int getUniqueIdentifier() { return METHOD_IDENTIFIER; } @Override public AbstractAuthenticationMethodOptionsPanel buildOptionsPanel(Context uiSharedContext) { return new ScriptBasedAuthenticationMethodOptionsPanel(); } @Override public boolean hasOptionsPanel() { return true; } @Override public AbstractCredentialsOptionsPanel<? extends AuthenticationCredentials> buildCredentialsOptionsPanel( AuthenticationCredentials credentials, Context uiSharedContext) { return new GenericAuthenticationCredentialsOptionsPanel( (GenericAuthenticationCredentials) credentials); } @Override public boolean hasCredentialsOptionsPanel() { return true; } @Override public boolean isTypeForMethod(AuthenticationMethod method) { return (method instanceof ScriptBasedAuthenticationMethod); } @Override public ScriptBasedAuthenticationMethod loadMethodFromSession(Session session, int contextId) throws DatabaseException { ScriptBasedAuthenticationMethod method = createAuthenticationMethod(contextId); // Load the script and make sure it still exists and still follows the required interface this.loadMethod(method, session.getContextDataStrings(contextId,RecordContext.TYPE_AUTH_METHOD_FIELD_1), session.getContextDataStrings(contextId,RecordContext.TYPE_AUTH_METHOD_FIELD_2)); return method; } public void loadMethod( ScriptBasedAuthenticationMethod method, List<String> scripts, List<String> paramValuesS) { // Load the script and make sure it still exists and still follows the required interface String scriptName = ""; if (scripts != null && scripts.size() > 0) { scriptName = scripts.get(0); ScriptWrapper script = getScriptsExtension().getScript(scriptName); if (script == null) { log.error("Unable to find script while loading Script Based Authentication Method for name: " + scriptName); if (View.isInitialised()) { View.getSingleton().showMessageDialog( Constant.messages.getString("authentication.method.script.load.errorScriptNotFound", scriptName)); } return; } log.info("Loaded script:" + script.getName()); method.script = script; // Check script interface and make sure we load the credentials parameter names AuthenticationScript s = getScriptInterfaceV2(script); if (s == null) { s = getScriptInterface(script); } if (s == null) { log.error("Unable to load Script Based Authentication method. The script " + scriptName + " does not properly implement the Authentication Script interface."); return; } try { if (s instanceof AuthenticationScriptV2) { AuthenticationScriptV2 sV2 = (AuthenticationScriptV2) s; method.setLoggedInIndicatorPattern(sV2.getLoggedInIndicator()); method.setLoggedOutIndicatorPattern(sV2.getLoggedOutIndicator()); } method.credentialsParamNames = s.getCredentialsParamsNames(); } catch (Exception e) { getScriptsExtension().handleScriptException(script, e); } } // Load the parameter values Map<String, String> paramValues = null; if (paramValuesS != null && paramValuesS.size() > 0) { paramValues = EncodingUtils.stringToMap(paramValuesS.get(0)); method.paramValues = paramValues; } else { method.paramValues = new HashMap<String, String>(); log.error("Unable to load script parameter values loading Script Based Authentication Method for name: " + scriptName); } } @Override public void persistMethodToSession(Session session, int contextId, AuthenticationMethod authMethod) throws UnsupportedAuthenticationMethodException, DatabaseException { if (!(authMethod instanceof ScriptBasedAuthenticationMethod)) throw new UnsupportedAuthenticationMethodException( "Script based authentication type only supports: " + ScriptBasedAuthenticationMethod.class); ScriptBasedAuthenticationMethod method = (ScriptBasedAuthenticationMethod) authMethod; session.setContextData(contextId, RecordContext.TYPE_AUTH_METHOD_FIELD_1, method.script.getName()); session.setContextData(contextId, RecordContext.TYPE_AUTH_METHOD_FIELD_2, EncodingUtils.mapToString(method.paramValues)); } @Override public AuthenticationCredentials createAuthenticationCredentials() { // NOTE: This method will initialize a set of Credentials without any required parameters // and, thus, should be later modified explicitly (e.g. through calls to decode()) return new GenericAuthenticationCredentials(new String[0]); } private ExtensionScript getScriptsExtension() { if (extensionScript == null) extensionScript = (ExtensionScript) Control.getSingleton().getExtensionLoader() .getExtension(ExtensionScript.NAME); return extensionScript; } private AuthenticationScript getScriptInterface(ScriptWrapper script) { try { return getScriptsExtension().getInterface(script, AuthenticationScript.class); } catch (Exception e) { getScriptsExtension().handleFailedScriptInterface( script, Constant.messages.getString("authentication.method.script.dialog.error.text.interface", script.getName())); } return null; } private AuthenticationScriptV2 getScriptInterfaceV2(ScriptWrapper script) { try { return getScriptsExtension().getInterface(script, AuthenticationScriptV2.class); } catch (Exception ignore) { // The interface is optional, the AuthenticationScript will be checked after this one. } return null; } /** * The Interface that needs to be implemented by an Authentication Script. */ public interface AuthenticationScript { public String[] getRequiredParamsNames(); public String[] getOptionalParamsNames(); public String[] getCredentialsParamsNames(); public HttpMessage authenticate(AuthenticationHelper helper, Map<String, String> paramsValues, GenericAuthenticationCredentials credentials) throws ScriptException; } /** * An {@code AuthenticationScript} that allows to specify the logged in/out indicators. * * @since 2.5.0 */ public interface AuthenticationScriptV2 extends AuthenticationScript { /** * Gets the logged in indicator pattern. * * @return the logged in indicator pattern */ String getLoggedInIndicator(); /** * Gets the logged out indicator pattern. * * @return the logged out indicator pattern */ String getLoggedOutIndicator(); } /* API related constants and methods. */ private static final String PARAM_SCRIPT_NAME = "scriptName"; private static final String PARAM_SCRIPT_CONFIG_PARAMS = "scriptConfigParams"; @Override public ApiDynamicActionImplementor getSetMethodForContextApiAction() { return new ApiDynamicActionImplementor(API_METHOD_NAME, new String[] { PARAM_SCRIPT_NAME }, new String[] { PARAM_SCRIPT_CONFIG_PARAMS }) { @Override public void handleAction(JSONObject params) throws ApiException { Context context = ApiUtils.getContextByParamId(params, AuthenticationAPI.PARAM_CONTEXT_ID); String scriptName = ApiUtils.getNonEmptyStringParam(params, PARAM_SCRIPT_NAME); // Prepare the method ScriptBasedAuthenticationMethod method = createAuthenticationMethod(context.getIndex()); // Load the script and make sure it exists and follows the required interface ScriptWrapper script = getScriptsExtension().getScript(scriptName); if (script == null) { log.error("Unable to find script while loading Script Based Authentication Method for name: " + scriptName); throw new ApiException(ApiException.Type.SCRIPT_NOT_FOUND, scriptName); } else log.info("Loaded script for API:" + script.getName()); method.script = script; // Check script interface and make sure we load the credentials parameter names AuthenticationScript s = getScriptInterfaceV2(script); if (s == null) { s = getScriptInterface(script); } if (s == null) { log.error("Unable to load Script Based Authentication method. The script " + script.getName() + " does not properly implement the Authentication Script interface."); throw new ApiException(ApiException.Type.BAD_SCRIPT_FORMAT, "Does not follow Authentication script interface"); } try { if (s instanceof AuthenticationScriptV2) { AuthenticationScriptV2 sV2 = (AuthenticationScriptV2) s; method.setLoggedInIndicatorPattern(sV2.getLoggedInIndicator()); method.setLoggedOutIndicatorPattern(sV2.getLoggedOutIndicator()); } method.credentialsParamNames = s.getCredentialsParamsNames(); // Load config param names + values and make sure all of the required ones // are there String[] requiredParams = s.getRequiredParamsNames(); String[] optionalParams = s.getOptionalParamsNames(); if (log.isDebugEnabled()) { log.debug("Loaded authentication script - required parameters: " + Arrays.toString(requiredParams) + " - optional parameters: " + Arrays.toString(optionalParams)); } Map<String, String> paramValues = new HashMap<String, String>(); for (String rp : requiredParams) { // If one of the required parameters is not present, it will throw // an exception String val = ApiUtils.getNonEmptyStringParam(params, rp); paramValues.put(rp, val); } for (String op : optionalParams) paramValues.put(op, ApiUtils.getOptionalStringParam(params, op)); method.paramValues = paramValues; if (log.isDebugEnabled()) log.debug("Loaded authentication script parameters:" + paramValues); } catch (ApiException e) { throw e; } catch (Exception e) { getScriptsExtension().handleScriptException(script, e); log.error("Unable to load Script Based Authentication method. The script " + script.getName() + " contains errors."); throw new ApiException(ApiException.Type.BAD_SCRIPT_FORMAT, e.getMessage()); } // Set the method, making sure that, if the type is different, things are changed // accordingly if (!context.getAuthenticationMethod().isSameType(method)) apiChangedAuthenticationMethodForContext(context.getIndex()); context.setAuthenticationMethod(method); } }; } @Override public ApiDynamicActionImplementor getSetCredentialsForUserApiAction() { return GenericAuthenticationCredentials.getSetCredentialsForUserApiAction(this); } @Override public void exportData(Configuration config, AuthenticationMethod authMethod) { if (!(authMethod instanceof ScriptBasedAuthenticationMethod)) { throw new UnsupportedAuthenticationMethodException( "Script based authentication type only supports: " + ScriptBasedAuthenticationMethod.class.getName()); } ScriptBasedAuthenticationMethod method = (ScriptBasedAuthenticationMethod) authMethod; config.setProperty(CONTEXT_CONFIG_AUTH_SCRIPT_NAME, method.script.getName()); config.setProperty(CONTEXT_CONFIG_AUTH_SCRIPT_PARAMS, EncodingUtils.mapToString(method.paramValues)); } @Override public void importData(Configuration config, AuthenticationMethod authMethod) throws ConfigurationException { if (!(authMethod instanceof ScriptBasedAuthenticationMethod)) { throw new UnsupportedAuthenticationMethodException( "Script based authentication type only supports: " + ScriptBasedAuthenticationMethod.class.getName()); } ScriptBasedAuthenticationMethod method = (ScriptBasedAuthenticationMethod) authMethod; this.loadMethod(method, objListToStrList(config.getList(CONTEXT_CONFIG_AUTH_SCRIPT_NAME)), objListToStrList(config.getList(CONTEXT_CONFIG_AUTH_SCRIPT_PARAMS))); } private List<String> objListToStrList(List<Object> oList) { List<String> sList = new ArrayList<String>(oList.size()); for (Object o : oList) { sList.add(o.toString()); } return sList; } }