New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add JSON-based authentication method #4624
Conversation
If it helps here's the diff of the extracted class: diff --git a/FormBasedAuthenticationMethodType.java b/PostBasedAuthenticationMethodType.java
index d2fd00212..104ab9266 100644
--- a/FormBasedAuthenticationMethodType.java
+++ b/PostBasedAuthenticationMethodType.java
@@ -1,37 +1,35 @@
/*
* Zed Attack Proxy (ZAP) and its related class files.
- *
+ *
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
- *
- * Copyright 2013 The ZAP Development Team
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ *
+ * Copyright 2018 The ZAP Development Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package org.zaproxy.zap.authentication;
import java.awt.Component;
import java.awt.GridBagLayout;
+import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.function.UnaryOperator;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
@@ -60,8 +58,6 @@ import org.parosproxy.paros.extension.ExtensionHook;
import org.parosproxy.paros.model.Model;
import org.parosproxy.paros.model.Session;
import org.parosproxy.paros.model.SiteNode;
-import org.parosproxy.paros.network.HtmlParameter;
-import org.parosproxy.paros.network.HtmlParameter.Type;
import org.parosproxy.paros.network.HttpHeader;
import org.parosproxy.paros.network.HttpMalformedHeaderException;
import org.parosproxy.paros.network.HttpMessage;
@@ -77,6 +73,7 @@ import org.zaproxy.zap.extension.authentication.AuthenticationAPI;
import org.zaproxy.zap.extension.authentication.ContextAuthenticationPanel;
import org.zaproxy.zap.extension.users.ExtensionUserManagement;
import org.zaproxy.zap.model.Context;
+import org.zaproxy.zap.model.NameValuePair;
import org.zaproxy.zap.session.SessionManagementMethod;
import org.zaproxy.zap.session.WebSession;
import org.zaproxy.zap.users.User;
@@ -88,42 +85,110 @@ import org.zaproxy.zap.view.popup.PopupMenuItemContext;
import org.zaproxy.zap.view.popup.PopupMenuItemSiteNodeContextMenuFactory;
/**
- * The implementation for an {@link AuthenticationMethodType} where the Users are authenticated by
- * posting a form with user and password.
+ * An {@link AuthenticationMethodType} where the Users are authenticated by POSTing the username and password.
+ * <p>
+ * The actual format of the POST body is defined by extending classes.
+ *
+ * @since TODO add version
*/
-public class FormBasedAuthenticationMethodType extends AuthenticationMethodType {
-
- public static final String CONTEXT_CONFIG_AUTH_FORM = AuthenticationMethod.CONTEXT_CONFIG_AUTH + ".form";
- public static final String CONTEXT_CONFIG_AUTH_FORM_LOGINURL = CONTEXT_CONFIG_AUTH_FORM + ".loginurl";
- public static final String CONTEXT_CONFIG_AUTH_FORM_LOGINBODY = CONTEXT_CONFIG_AUTH_FORM + ".loginbody";
-
- private static final int METHOD_IDENTIFIER = 2;
-
- /** The Authentication method's name. */
- private static final String METHOD_NAME = Constant.messages.getString("authentication.method.fb.name");
+public abstract class PostBasedAuthenticationMethodType extends AuthenticationMethodType {
+
+ private static final String CONTEXT_CONFIG_AUTH_FORM = AuthenticationMethod.CONTEXT_CONFIG_AUTH + ".form";
+ private static final String CONTEXT_CONFIG_AUTH_FORM_LOGINURL = CONTEXT_CONFIG_AUTH_FORM + ".loginurl";
+ private static final String CONTEXT_CONFIG_AUTH_FORM_LOGINBODY = CONTEXT_CONFIG_AUTH_FORM + ".loginbody";
+
+ private static final String POST_DATA_LABEL = Constant.messages
+ .getString("authentication.method.pb.field.label.postData");
+ private static final String POST_DATA_REQUIRED_LABEL = Constant.messages
+ .getString("authentication.method.pb.field.label.postDataRequired");
+ private static final String USERNAME_PARAM_LABEL = Constant.messages
+ .getString("authentication.method.pb.field.label.usernameParam");
+ private static final String PASSWORD_PARAM_LABEL = Constant.messages
+ .getString("authentication.method.pb.field.label.passwordParam");
+ private static final String LOGIN_URL_LABEL = Constant.messages
+ .getString("authentication.method.pb.field.label.loginUrl");
+ private static final String AUTH_DESCRIPTION = Constant.messages
+ .getString("authentication.method.pb.field.label.description");
+
+ private static final Logger log = Logger.getLogger(PostBasedAuthenticationMethodType.class);
+
+ private final String methodName;
+ private final int methodIdentifier;
+ private final String apiMethodName;
+ private final String labelPopupMenuKey;
+ private final boolean postDataRequired;
- private static final String API_METHOD_NAME = "formBasedAuthentication";
-
- private static final Logger log = Logger.getLogger(FormBasedAuthenticationMethodType.class);
+ /**
+ * Constructs a {@code PostBasedAuthenticationMethodType} with the given data.
+ *
+ * @param methodName the name of the authentication method, should not be {@code null}.
+ * @param methodIdentifier the ID of the authentication method.
+ * @param apiMethodName the API name of the authentication method, should not be {@code null}.
+ * @param labelPopupMenuKey the name of the menu item that flags the request as login.
+ * @param postDataRequired {@code true} if the POST data is required by the authentication method, {@code false} otherwise.
+ */
+ protected PostBasedAuthenticationMethodType(
+ String methodName,
+ int methodIdentifier,
+ String apiMethodName,
+ String labelPopupMenuKey,
+ boolean postDataRequired) {
+ this.methodName = methodName;
+ this.methodIdentifier = methodIdentifier;
+ this.apiMethodName = apiMethodName;
+ this.labelPopupMenuKey = labelPopupMenuKey;
+ this.postDataRequired = postDataRequired;
+ }
/**
- * The implementation for an {@link AuthenticationMethod} where the Users are authenticated by
- * posting a form with user and password.
+ * An {@link AuthenticationMethod} where the Users are authenticated by POSTing the username and password.
+ * <p>
+ * The actual format of the POST body is defined by extending classes.
*/
- public static class FormBasedAuthenticationMethod extends AuthenticationMethod {
+ public abstract class PostBasedAuthenticationMethod extends AuthenticationMethod {
private static final String LOGIN_ICON_RESOURCE = "/resource/icon/fugue/door-open-green-arrow.png";
public static final String MSG_USER_PATTERN = "{%username%}";
public static final String MSG_PASS_PATTERN = "{%password%}";
+ private final String contentType;
+ private final UnaryOperator<String> paramEncoder;
+
private HttpSender httpSender;
private SiteNode markedLoginSiteNode;
private SiteNode loginSiteNode = null;
private String loginRequestURL;
private String loginRequestBody;
+ /**
+ * Constructs a {@code PostBasedAuthenticationMethod} with the given data.
+ *
+ * @param contentType the value of the Content-Type, to be added to the authentication message-
+ * @param paramEncoder the encoded of parameters, used to encode the authentication credentials in the POST body.
+ * @param authenticationMethod the authentication method to copy from, might be {@code null}.
+ */
+ protected PostBasedAuthenticationMethod(
+ String contentType,
+ UnaryOperator<String> paramEncoder,
+ PostBasedAuthenticationMethod authenticationMethod) {
+ this.contentType = contentType + "; charset=utf-8";
+ this.paramEncoder = paramEncoder;
+ if (authenticationMethod != null) {
+ this.loginRequestURL = authenticationMethod.loginRequestURL;
+ this.loginRequestBody = authenticationMethod.loginRequestBody;
+ this.loginSiteNode = authenticationMethod.loginSiteNode;
+ this.markedLoginSiteNode = authenticationMethod.markedLoginSiteNode;
+ }
+ }
+
@Override
public boolean isConfigured() {
+ if (postDataRequired) {
+ if (loginRequestBody == null || loginRequestBody.isEmpty()) {
+ return false;
+ }
+ }
+
// check if the login url is valid
return loginRequestURL != null && !loginRequestURL.isEmpty();
}
@@ -133,11 +198,6 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
return new UsernamePasswordAuthenticationCredentials();
}
- @Override
- public AuthenticationMethodType getType() {
- return new FormBasedAuthenticationMethodType();
- }
-
protected HttpSender getHttpSender() {
if (this.httpSender == null) {
this.httpSender = new HttpSender(Model.getSingleton().getOptionsParam().getConnectionParam(),
@@ -156,7 +216,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
* @throws HttpMalformedHeaderException if the constructed HTTP request is malformed
* @throws DatabaseException if an error occurred while reading the request from database
*/
- private HttpMessage prepareRequestMessage(UsernamePasswordAuthenticationCredentials credentials)
+ protected HttpMessage prepareRequestMessage(UsernamePasswordAuthenticationCredentials credentials)
throws URIException, HttpMalformedHeaderException, DatabaseException {
URI requestURI = createLoginUrl(loginRequestURL, credentials.getUsername(), credentials.getPassword());
@@ -164,7 +224,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
// Replace the username and password in the post data of the request, if needed
String requestBody = null;
if (loginRequestBody != null && !loginRequestBody.isEmpty()) {
- requestBody = replaceUserData(loginRequestBody, credentials.getUsername(), credentials.getPassword());
+ requestBody = replaceUserData(loginRequestBody, credentials.getUsername(), credentials.getPassword(), paramEncoder);
}
// Prepare the actual message, either based on the existing one, or create a new one
@@ -184,6 +244,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
new HttpRequestHeader(method, requestURI, HttpHeader.HTTP10,
Model.getSingleton().getOptionsParam().getConnectionParam()));
if (requestBody != null) {
+ requestMessage.getRequestHeader().setHeader(HttpHeader.CONTENT_TYPE, contentType);
requestMessage.getRequestBody().setBody(requestBody);
}
}
@@ -199,7 +260,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
// type check
if (!(credentials instanceof UsernamePasswordAuthenticationCredentials)) {
throw new UnsupportedAuthenticationCredentialsException(
- "Form based authentication method only supports "
+ "Post based authentication method only supports "
+ UsernamePasswordAuthenticationCredentials.class.getSimpleName()
+ ". Received: " + credentials.getClass());
}
@@ -345,17 +406,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public String toString() {
- return "FormBasedAuthenticationMethod [loginURI=" + loginRequestURL + "]";
- }
-
- @Override
- public FormBasedAuthenticationMethod duplicate() {
- FormBasedAuthenticationMethod clonedMethod = new FormBasedAuthenticationMethod();
- clonedMethod.loginRequestURL = this.loginRequestURL;
- clonedMethod.loginRequestBody = this.loginRequestBody;
- clonedMethod.loginSiteNode = this.loginSiteNode;
- clonedMethod.markedLoginSiteNode = this.markedLoginSiteNode;
- return clonedMethod;
+ return getClass().getSimpleName() + " [loginURI=" + loginRequestURL + "]";
}
@Override
@@ -371,7 +422,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public ApiResponse getApiResponseRepresentation() {
Map<String, String> values = new HashMap<>();
- values.put("methodName", API_METHOD_NAME);
+ values.put("methodName", apiMethodName);
values.put("loginUrl", loginRequestURL);
values.put("loginRequestData", this.loginRequestBody);
return new AuthMethodApiResponseRepresentation<>(values);
@@ -394,7 +445,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
return false;
if (getClass() != obj.getClass())
return false;
- FormBasedAuthenticationMethod other = (FormBasedAuthenticationMethod) obj;
+ PostBasedAuthenticationMethod other = (PostBasedAuthenticationMethod) obj;
if (loginRequestBody == null) {
if (other.loginRequestBody != null)
return false;
@@ -410,12 +461,12 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
private static URI createLoginUrl(String loginData, String username, String password) throws URIException {
- return new URI(replaceUserData(loginData, username, password), true);
+ return new URI(replaceUserData(loginData, username, password, PostBasedAuthenticationMethodType::encodeParameter), true);
}
- private static String replaceUserData(String loginData, String username, String password) {
- return loginData.replace(FormBasedAuthenticationMethod.MSG_USER_PATTERN, encodeParameter(username))
- .replace(FormBasedAuthenticationMethod.MSG_PASS_PATTERN, encodeParameter(password));
+ private static String replaceUserData(String loginData, String username, String password, UnaryOperator<String> encoder) {
+ return loginData.replace(PostBasedAuthenticationMethod.MSG_USER_PATTERN, encoder.apply(username))
+ .replace(PostBasedAuthenticationMethod.MSG_PASS_PATTERN, encoder.apply(password));
}
private static String encodeParameter(String parameter) {
@@ -441,37 +492,29 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
/**
- * The Options Panel used for configuring a {@link FormBasedAuthenticationMethod}.
+ * The Options Panel used for configuring a {@link PostBasedAuthenticationMethod}.
*/
- private static class FormBasedAuthenticationMethodOptionsPanel extends
+ protected abstract class PostBasedAuthenticationMethodOptionsPanel extends
AbstractAuthenticationMethodOptionsPanel {
- private static final long serialVersionUID = -9010956260384814566L;
-
- private static final String POST_DATA_LABEL = Constant.messages
- .getString("authentication.method.fb.field.label.postData");
- private static final String USERNAME_PARAM_LABEL = Constant.messages
- .getString("authentication.method.fb.field.label.usernameParam");
- private static final String PASSWORD_PARAM_LABEL = Constant.messages
- .getString("authentication.method.fb.field.label.passwordParam");
- private static final String LOGIN_URL_LABEL = Constant.messages
- .getString("authentication.method.fb.field.label.loginUrl");
- private static final String AUTH_DESCRIPTION = Constant.messages
- .getString("authentication.method.fb.field.label.description");
+ private static final long serialVersionUID = 1L;
private ZapTextField loginUrlField;
private ZapTextField postDataField;
- private JComboBox<HtmlParameter> usernameParameterCombo;
- private JComboBox<HtmlParameter> passwordParameterCombo;
- private FormBasedAuthenticationMethod authenticationMethod;
+ private JComboBox<NameValuePair> usernameParameterCombo;
+ private JComboBox<NameValuePair> passwordParameterCombo;
+ private PostBasedAuthenticationMethod authenticationMethod;
private Context context;
private ExtensionUserManagement userExt = null;
- public FormBasedAuthenticationMethodOptionsPanel(Context context) {
+ private final UnaryOperator<String> paramDecoder;
+
+ public PostBasedAuthenticationMethodOptionsPanel(Context context, UnaryOperator<String> paramDecoder) {
super();
initialize();
this.context = context;
+ this.paramDecoder = paramDecoder;
}
@SuppressWarnings("unchecked")
@@ -518,7 +561,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
if (node != null && node.getHistoryReference() != null) {
try {
if (log.isInfoEnabled()) {
- log.info("Selected Form Based Auth Login URL via dialog: "
+ log.info("Selected Post Based Auth Login URL via dialog: "
+ node.getHistoryReference().getURI().toString());
}
@@ -537,56 +580,56 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
urlSelectPanel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D));
this.add(urlSelectPanel, LayoutHelper.getGBC(0, 1, 2, 1.0d, 0.0d));
- this.add(new JLabel(POST_DATA_LABEL), LayoutHelper.getGBC(0, 2, 2, 1.0d, 0.0d));
+ this.add(new JLabel(postDataRequired ? POST_DATA_REQUIRED_LABEL : POST_DATA_LABEL), LayoutHelper.getGBC(0, 2, 2, 1.0d, 0.0d));
this.add(this.postDataField, LayoutHelper.getGBC(0, 3, 2, 1.0d, 0.0d));
this.add(new JLabel(USERNAME_PARAM_LABEL), LayoutHelper.getGBC(0, 4, 1, 1.0d, 0.0d));
this.usernameParameterCombo = new JComboBox<>();
- this.usernameParameterCombo.setRenderer(new HtmlParameterRenderer());
+ this.usernameParameterCombo.setRenderer(NameValuePairRenderer.INSTANCE);
this.add(usernameParameterCombo, LayoutHelper.getGBC(0, 5, 1, 1.0d, 0.0d));
this.add(new JLabel(PASSWORD_PARAM_LABEL), LayoutHelper.getGBC(1, 4, 1, 1.0d, 0.0d));
this.passwordParameterCombo = new JComboBox<>();
- this.passwordParameterCombo.setRenderer(new HtmlParameterRenderer());
+ this.passwordParameterCombo.setRenderer(NameValuePairRenderer.INSTANCE);
this.add(passwordParameterCombo, LayoutHelper.getGBC(1, 5, 1, 1.0d, 0.0d));
this.add(new JLabel(AUTH_DESCRIPTION), LayoutHelper.getGBC(0, 8, 2, 1.0d, 0.0d));
// Make sure we update the parameters when something has been changed in the
// postDataField
- this.postDataField.addFocusListener(new FocusListener() {
+ this.postDataField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
updateParameters();
}
-
- @Override
- public void focusGained(FocusEvent e) {
- }
});
}
+ /**
+ * Gets the context being configured.
+ *
+ * @return the context, never {@code null}.
+ */
+ protected Context getContext() {
+ return context;
+ }
+
@Override
public void validateFields() {
if (!isValidLoginUrl(loginUrlField.getText())) {
loginUrlField.requestFocusInWindow();
throw new IllegalStateException(
- Constant.messages.getString("authentication.method.fb.dialog.error.url.text"));
+ Constant.messages.getString("authentication.method.pb.dialog.error.url.text"));
}
- }
- private String replaceParameterValue(String originalString, HtmlParameter parameter,
- String replaceString) {
- String keyValueSeparator = context.getPostParamParser().getDefaultKeyValueSeparator();
- String nameAndSeparator = parameter.getName() + keyValueSeparator;
- // Make sure we handle the case when there's only the parameter name in the POST data instead of
- // parameter name + separator + value (e.g. just 'param1&...' instead of 'param1=...&...')
- if (originalString.contains(nameAndSeparator))
- return originalString.replace(nameAndSeparator + parameter.getValue(), nameAndSeparator
- + replaceString);
- else
- return originalString.replace(parameter.getName(), nameAndSeparator + replaceString);
+ if (postDataRequired && postDataField.getText().isEmpty()) {
+ postDataField.requestFocusInWindow();
+ throw new IllegalStateException(
+ Constant.messages.getString("authentication.method.pb.dialog.error.postData.text"));
+ }
}
+
+ protected abstract String replaceParameterValue(String originalString, NameValuePair parameter, String replaceString);
private ExtensionUserManagement getUserExt() {
if (userExt == null) {
@@ -601,19 +644,18 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
try {
String postData = postDataField.getText();
if (!postData.isEmpty()) {
- HtmlParameter userParam = (HtmlParameter) usernameParameterCombo.getSelectedItem();
- HtmlParameter passwdParam = (HtmlParameter) passwordParameterCombo.getSelectedItem();
+ NameValuePair userParam = (NameValuePair) usernameParameterCombo.getSelectedItem();
+ NameValuePair passwdParam = (NameValuePair) passwordParameterCombo.getSelectedItem();
ExtensionUserManagement userExt = getUserExt();
if (userExt != null && userExt.getUIConfiguredUsers(context.getIndex()).size() == 0) {
String username = userParam.getValue();
String password = passwdParam.getValue();
- if (!username.isEmpty() && !username.contains(FormBasedAuthenticationMethod.MSG_USER_PATTERN)
- && !password.contains(FormBasedAuthenticationMethod.MSG_PASS_PATTERN)) {
+ if (!username.isEmpty() && !username.contains(PostBasedAuthenticationMethod.MSG_USER_PATTERN)
+ && !password.contains(PostBasedAuthenticationMethod.MSG_PASS_PATTERN)) {
// Add the user based on the details provided
- // Note that right now application/x-www-form-urlencoded forms are supported
- String userStr = decodeValue(username);
- String passwdStr = decodeValue(password);
+ String userStr = paramDecoder.apply(username);
+ String passwdStr = paramDecoder.apply(password);
if (!userStr.isEmpty() && !passwdStr.isEmpty()) {
User user = new User(context.getIndex(), userStr);
UsernamePasswordAuthenticationCredentials upac =
@@ -625,9 +667,9 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
postData = this.replaceParameterValue(postData, userParam,
- FormBasedAuthenticationMethod.MSG_USER_PATTERN);
+ PostBasedAuthenticationMethod.MSG_USER_PATTERN);
postData = this.replaceParameterValue(postData, passwdParam,
- FormBasedAuthenticationMethod.MSG_PASS_PATTERN);
+ PostBasedAuthenticationMethod.MSG_PASS_PATTERN);
}
getMethod().setLoginRequest(loginUrlField.getText(), postData);
} catch (Exception e) {
@@ -635,20 +677,9 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
}
- private static String decodeValue(String value) {
- try {
- return URLDecoder.decode(value, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException ignore) {
- // Standard charset.
- } catch (IllegalArgumentException e) {
- log.debug("Failed to URL decode: " + value, e);
- }
- return "";
- }
-
@Override
public void bindMethod(AuthenticationMethod method) {
- this.authenticationMethod = (FormBasedAuthenticationMethod) method;
+ this.authenticationMethod = (PostBasedAuthenticationMethod) method;
this.loginUrlField.setText(authenticationMethod.loginRequestURL);
this.postDataField.setText(authenticationMethod.loginRequestBody);
@@ -662,28 +693,27 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
* @param value the value
* @return the index of param with value, or -1 if no match was found
*/
- private int getIndexOfParamWithValue(HtmlParameter[] params, String value) {
+ private int getIndexOfParamWithValue(NameValuePair[] params, String value) {
for (int i = 0; i < params.length; i++)
- if (params[i].getValue().equals(value))
+ if (value.equals(params[i].getValue()))
return i;
return -1;
}
private void updateParameters() {
try {
- Map<String, String> params = this.context.getPostParamParser().parse(
- this.postDataField.getText());
- HtmlParameter[] paramsArray = mapToParamArray(params);
+ List<NameValuePair> params = extractParameters(this.postDataField.getText());
+ NameValuePair[] paramsArray = params.toArray(new NameValuePair[params.size()]);
this.usernameParameterCombo.setModel(new DefaultComboBoxModel<>(paramsArray));
this.passwordParameterCombo.setModel(new DefaultComboBoxModel<>(paramsArray));
int index = getIndexOfParamWithValue(paramsArray,
- FormBasedAuthenticationMethod.MSG_USER_PATTERN);
+ PostBasedAuthenticationMethod.MSG_USER_PATTERN);
if (index >= 0) {
this.usernameParameterCombo.setSelectedIndex(index);
}
- index = getIndexOfParamWithValue(paramsArray, FormBasedAuthenticationMethod.MSG_PASS_PATTERN);
+ index = getIndexOfParamWithValue(paramsArray, PostBasedAuthenticationMethod.MSG_PASS_PATTERN);
if (index >= 0) {
this.passwordParameterCombo.setSelectedIndex(index);
}
@@ -692,28 +722,29 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
}
- private HtmlParameter[] mapToParamArray(Map<String, String> map) {
- HtmlParameter[] array = new HtmlParameter[map.size()];
- int i = 0;
- for (Entry<String, String> param : map.entrySet()) {
- array[i++] = new HtmlParameter(Type.form, param.getKey(), param.getValue());
- }
- return array;
- }
+ protected abstract List<NameValuePair> extractParameters(String postData);
@Override
- public FormBasedAuthenticationMethod getMethod() {
+ public PostBasedAuthenticationMethod getMethod() {
return this.authenticationMethod;
}
}
/**
- * A renderer for properly displaying the name of an HtmlParameter in a ComboBox.
+ * A renderer for properly displaying the name of a {@link NameValuePair} in a ComboBox.
+ *
+ * @see #INSTANCE
*/
- private static class HtmlParameterRenderer extends BasicComboBoxRenderer {
+ private static class NameValuePairRenderer extends BasicComboBoxRenderer {
+
+ public static final NameValuePairRenderer INSTANCE = new NameValuePairRenderer();
+
private static final long serialVersionUID = 3654541772447187317L;
private static final Border BORDER = new EmptyBorder(2, 3, 3, 3);
+ private NameValuePairRenderer() {
+ }
+
@Override
@SuppressWarnings("rawtypes")
public Component getListCellRendererComponent(JList list, Object value, int index,
@@ -721,7 +752,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
setBorder(BORDER);
- HtmlParameter item = (HtmlParameter) value;
+ NameValuePair item = (NameValuePair) value;
setText(item.getName());
}
return this;
@@ -729,18 +760,11 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
}
@Override
- public FormBasedAuthenticationMethod createAuthenticationMethod(int contextId) {
- return new FormBasedAuthenticationMethod();
- }
+ public abstract PostBasedAuthenticationMethod createAuthenticationMethod(int contextId);
@Override
public String getName() {
- return METHOD_NAME;
- }
-
- @Override
- public AbstractAuthenticationMethodOptionsPanel buildOptionsPanel(Context uiSharedContext) {
- return new FormBasedAuthenticationMethodOptionsPanel(uiSharedContext);
+ return methodName;
}
@Override
@@ -760,11 +784,6 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
return true;
}
- @Override
- public boolean isTypeForMethod(AuthenticationMethod method) {
- return (method instanceof FormBasedAuthenticationMethod);
- }
-
@Override
public void hook(ExtensionHook extensionHook) {
extensionHook.getHookMenu().addPopupMenuItem(getPopupFlagLoginRequestMenuFactory());
@@ -776,14 +795,14 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
* @return the popup flag login request menu factory
*/
private PopupMenuItemSiteNodeContextMenuFactory getPopupFlagLoginRequestMenuFactory() {
- PopupMenuItemSiteNodeContextMenuFactory popupFlagLoginRequestMenuFactory = new PopupMenuItemSiteNodeContextMenuFactory(
+ PopupMenuItemSiteNodeContextMenuFactory popupFlagLoginRequestMenuFactory = new PopupMenuItemSiteNodeContextMenuFactory(
Constant.messages.getString("context.flag.popup")) {
private static final long serialVersionUID = 8927418764L;
@Override
public PopupMenuItemContext getContextMenu(Context context, String parentMenu) {
return new PopupMenuItemContext(context, parentMenu,
- Constant.messages.getString("authentication.method.fb.popup.login.request", context.getName())) {
+ Constant.messages.getString(labelPopupMenuKey, context.getName())) {
private static final long serialVersionUID = 1967885623005183801L;
private ExtensionUserManagement usersExtension;
@@ -821,10 +840,10 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
uiSharedContext = sessionDialog.getUISharedContext(this.getContext().getIndex());
// Do the work/changes on the UI shared context
- if (this.getContext().getAuthenticationMethod() instanceof FormBasedAuthenticationMethod) {
- log.info("Selected new login request via PopupMenu. Changing existing Form-Based Authentication instance for Context "
+ if (isTypeForMethod(this.getContext().getAuthenticationMethod())) {
+ log.info("Selected new login request via PopupMenu. Changing existing " + methodName + " instance for Context "
+ getContext().getIndex());
- FormBasedAuthenticationMethod method = (FormBasedAuthenticationMethod) uiSharedContext
+ PostBasedAuthenticationMethod method = (PostBasedAuthenticationMethod) uiSharedContext
.getAuthenticationMethod();
try {
@@ -841,9 +860,9 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
ContextAuthenticationPanel
.buildName(this.getContext().getIndex()), false);
} else {
- log.info("Selected new login request via PopupMenu. Creating new Form-Based Authentication instance for Context "
+ log.info("Selected new login request via PopupMenu. Creating new " + methodName + " instance for Context "
+ getContext().getIndex());
- FormBasedAuthenticationMethod method = new FormBasedAuthenticationMethod();
+ PostBasedAuthenticationMethod method = createAuthenticationMethod(getContext().getIndex());
try {
method.setLoginRequest(sn);
@@ -891,7 +910,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public AuthenticationMethod loadMethodFromSession(Session session, int contextId) throws DatabaseException {
- FormBasedAuthenticationMethod method = new FormBasedAuthenticationMethod();
+ PostBasedAuthenticationMethod method = createAuthenticationMethod(contextId);
List<String> urls = session.getContextDataStrings(contextId, RecordContext.TYPE_AUTH_METHOD_FIELD_1);
String url = "";
if (urls != null && urls.size() > 0) {
@@ -908,7 +927,7 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
try {
method.setLoginRequest(url, postData);
} catch (Exception e) {
- log.error("Unable to load FormBasedAuthenticationMethod. ", e);
+ log.error("Unable to load Post based authentication method data:", e);
}
return method;
}
@@ -916,19 +935,19 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public void persistMethodToSession(Session session, int contextId, AuthenticationMethod authMethod)
throws DatabaseException {
- if (!(authMethod instanceof FormBasedAuthenticationMethod)) {
+ if (!(authMethod instanceof PostBasedAuthenticationMethod)) {
throw new UnsupportedAuthenticationMethodException(
- "Form based authentication type only supports: " + FormBasedAuthenticationMethod.class);
+ "Post based authentication type only supports: " + PostBasedAuthenticationMethod.class);
}
- FormBasedAuthenticationMethod method = (FormBasedAuthenticationMethod) authMethod;
+ PostBasedAuthenticationMethod method = (PostBasedAuthenticationMethod) authMethod;
session.setContextData(contextId, RecordContext.TYPE_AUTH_METHOD_FIELD_1, method.loginRequestURL);
session.setContextData(contextId, RecordContext.TYPE_AUTH_METHOD_FIELD_2, method.loginRequestBody);
}
@Override
public int getUniqueIdentifier() {
- return METHOD_IDENTIFIER;
+ return methodIdentifier;
}
@Override
@@ -942,8 +961,16 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public ApiDynamicActionImplementor getSetMethodForContextApiAction() {
- return new ApiDynamicActionImplementor(API_METHOD_NAME, new String[] { PARAM_LOGIN_URL },
- new String[] { PARAM_LOGIN_REQUEST_DATA }) {
+ String[] mandatoryParamNames;
+ String[] optionalParamNames;
+ if (postDataRequired) {
+ mandatoryParamNames = new String[] { PARAM_LOGIN_URL, PARAM_LOGIN_REQUEST_DATA };
+ optionalParamNames = null;
+ } else {
+ mandatoryParamNames = new String[] { PARAM_LOGIN_URL };
+ optionalParamNames = new String[] { PARAM_LOGIN_REQUEST_DATA };
+ }
+ return new ApiDynamicActionImplementor(apiMethodName, mandatoryParamNames, optionalParamNames) {
@Override
public void handleAction(JSONObject params) throws ApiException {
@@ -953,12 +980,14 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_LOGIN_URL);
}
String postData = "";
- if (params.containsKey(PARAM_LOGIN_REQUEST_DATA)) {
+ if (postDataRequired) {
+ postData = ApiUtils.getNonEmptyStringParam(params, PARAM_LOGIN_REQUEST_DATA);
+ } else if (params.containsKey(PARAM_LOGIN_REQUEST_DATA)) {
postData = params.getString(PARAM_LOGIN_REQUEST_DATA);
}
// Set the method
- FormBasedAuthenticationMethod method = createAuthenticationMethod(context.getIndex());
+ PostBasedAuthenticationMethod method = createAuthenticationMethod(context.getIndex());
try {
method.setLoginRequest(loginUrl, postData);
} catch (Exception e) {
@@ -979,11 +1008,11 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public void exportData(Configuration config, AuthenticationMethod authMethod) {
- if (!(authMethod instanceof FormBasedAuthenticationMethod)) {
+ if (!(authMethod instanceof PostBasedAuthenticationMethod)) {
throw new UnsupportedAuthenticationMethodException(
- "Form based authentication type only supports: " + FormBasedAuthenticationMethod.class.getName());
+ "Post based authentication type only supports: " + PostBasedAuthenticationMethod.class.getName());
}
- FormBasedAuthenticationMethod method = (FormBasedAuthenticationMethod) authMethod;
+ PostBasedAuthenticationMethod method = (PostBasedAuthenticationMethod) authMethod;
config.setProperty(CONTEXT_CONFIG_AUTH_FORM_LOGINURL, method.loginRequestURL);
config.setProperty(CONTEXT_CONFIG_AUTH_FORM_LOGINBODY, method.loginRequestBody);
@@ -991,11 +1020,11 @@ public class FormBasedAuthenticationMethodType extends AuthenticationMethodType
@Override
public void importData(Configuration config, AuthenticationMethod authMethod) throws ConfigurationException {
- if (!(authMethod instanceof FormBasedAuthenticationMethod)) {
+ if (!(authMethod instanceof PostBasedAuthenticationMethod)) {
throw new UnsupportedAuthenticationMethodException(
- "Form based authentication type only supports: " + FormBasedAuthenticationMethod.class.getName());
+ "Post based authentication type only supports: " + PostBasedAuthenticationMethod.class.getName());
}
- FormBasedAuthenticationMethod method = (FormBasedAuthenticationMethod) authMethod;
+ PostBasedAuthenticationMethod method = (PostBasedAuthenticationMethod) authMethod;
try {
method.setLoginRequest(config.getString(CONTEXT_CONFIG_AUTH_FORM_LOGINURL), |
src/org/zaproxy/zap/authentication/JsonBasedAuthenticationMethodType.java
Outdated
Show resolved
Hide resolved
src/org/zaproxy/zap/authentication/JsonBasedAuthenticationMethodType.java
Show resolved
Hide resolved
src/org/zaproxy/zap/authentication/PostBasedAuthenticationMethodType.java
Outdated
Show resolved
Hide resolved
src/org/zaproxy/zap/authentication/PostBasedAuthenticationMethodType.java
Outdated
Show resolved
Hide resolved
src/org/zaproxy/zap/authentication/PostBasedAuthenticationMethodType.java
Outdated
Show resolved
Hide resolved
Add an authentication method, JsonBasedAuthenticationMethodType, that allows to send a JSON object in the request body. It can be configured through the API with the name "jsonBasedAuthentication". Extract a class, PostBasedAuthenticationMethodType, to be used by FormBasedAuthenticationMethodType and the new auth method, the behaviour is exactly the same except for the data they handle (application/json or application/x-www-form-urlencoded) and the POST data required. Add libraries used to quote the authentication credentials when injected into the request body. Add JSON Content-Type to HttpHeader. Fix zaproxy#2439 - Configure Authentication with Json object
5a97ab0
to
181384e
Compare
@kingthorin @psiinon is there an eta when this will make it into stable and will that be 2.8.0? |
@kirksl We havnt planned when 2.8.0 will be yet I'm afraid. We're aiming for ~ 2 releases a year, so maybe within the next few months. |
@psiinon no worries. we're happy to use the weekly releases. are they stable enough if we're just doing passive, active scans on our nightly CI builds? |
They might break occasionally, but we react quickly to fix it. |
We've only had to fix them a couple of times in the last couple of years. |
Most likely tomorrow (live image already includes this though). |
The weekly docker image which includes this change is available now :) |
Cheers mate. Greatly appreciate it. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Add an authentication method, JsonBasedAuthenticationMethodType, that
allows to send a JSON object in the request body. It can be configured
through the API with the name "jsonBasedAuthentication".
Extract a class, PostBasedAuthenticationMethodType, to be used by
FormBasedAuthenticationMethodType and the new auth method, the behaviour
is exactly the same except for the data they handle (application/json or
application/x-www-form-urlencoded) and the POST data required.
Add libraries used to quote the authentication credentials when injected
into the request body.
Add JSON Content-Type to HttpHeader.
Fix #2439 - Configure Authentication with Json object