/* * 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. */ package org.zaproxy.zap.extension.authentication; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.db.DatabaseException; import org.parosproxy.paros.db.RecordContext; import org.parosproxy.paros.extension.ExtensionAdaptor; import org.parosproxy.paros.extension.ExtensionHook; import org.parosproxy.paros.extension.ExtensionPopupMenuItem; import org.parosproxy.paros.model.Model; import org.parosproxy.paros.model.Session; import org.zaproxy.zap.authentication.AuthenticationMethod; import org.zaproxy.zap.authentication.AuthenticationMethodType; import org.zaproxy.zap.authentication.FormBasedAuthenticationMethodType; import org.zaproxy.zap.authentication.FormBasedAuthenticationMethodType.FormBasedAuthenticationMethod; import org.zaproxy.zap.authentication.HttpAuthenticationMethodType; import org.zaproxy.zap.authentication.ManualAuthenticationMethodType; import org.zaproxy.zap.authentication.ScriptBasedAuthenticationMethodType; import org.zaproxy.zap.extension.stdmenus.PopupContextMenuItemFactory; import org.zaproxy.zap.model.Context; import org.zaproxy.zap.model.ContextDataFactory; import org.zaproxy.zap.view.AbstractContextPropertiesPanel; import org.zaproxy.zap.view.ContextPanelFactory; /** * The Extension that handles Authentication methods, in correlation with Contexts. */ public class ExtensionAuthentication extends ExtensionAdaptor implements ContextPanelFactory, ContextDataFactory { public static final int EXTENSION_ORDER = 52; /** The NAME of the extension. */ public static final String NAME = "ExtensionAuthentication"; /** The Constant log. */ private static final Logger log = Logger.getLogger(ExtensionAuthentication.class); /** The automatically loaded authentication method types. */ List<AuthenticationMethodType> authenticationMethodTypes; /** The context panels map. */ private Map<Integer, ContextAuthenticationPanel> contextPanelsMap = new HashMap<>(); private PopupContextMenuItemFactory popupFlagLoggedInIndicatorMenuFactory; private PopupContextMenuItemFactory popupFlagLoggedOutIndicatorMenuFactory; AuthenticationAPI api; public ExtensionAuthentication() { super(); initialize(); } /** * Initialize the extension. */ private void initialize() { this.setName(NAME); this.setOrder(EXTENSION_ORDER); } @Override public void hook(ExtensionHook extensionHook) { super.hook(extensionHook); // Register this as a context data factory Model.getSingleton().addContextDataFactory(this); if (getView() != null) { extensionHook.getHookMenu().addPopupMenuItem(getPopupFlagLoggedInIndicatorMenu()); extensionHook.getHookMenu().addPopupMenuItem(getPopupFlagLoggedOutIndicatorMenu()); // Factory for generating Session Context UserAuth panels getView().addContextPanelFactory(this); } // Load the Authentication and Session Management methods this.loadAuthenticationMethodTypes(extensionHook); // Register the api this.api = new AuthenticationAPI(this); extensionHook.addApiImplementor(api); } @Override public AbstractContextPropertiesPanel getContextPanel(Context context) { ContextAuthenticationPanel panel = this.contextPanelsMap.get(context.getIndex()); if (panel == null) { panel = new ContextAuthenticationPanel(this, context); this.contextPanelsMap.put(context.getIndex(), panel); } return panel; } @Override public URL getURL() { try { return new URL(Constant.ZAP_HOMEPAGE); } catch (MalformedURLException e) { return null; } } @Override public String getAuthor() { return Constant.ZAP_TEAM; } /** * Gets the popup menu for flagging the "Logged in" pattern. * * @return the popup menu */ private PopupContextMenuItemFactory getPopupFlagLoggedInIndicatorMenu() { if (this.popupFlagLoggedInIndicatorMenuFactory == null) { popupFlagLoggedInIndicatorMenuFactory = new PopupContextMenuItemFactory("dd - " + Constant.messages.getString("context.flag.popup")) { private static final long serialVersionUID = 2453839120088204122L; @Override public ExtensionPopupMenuItem getContextMenu(Context context, String parentMenu) { return new PopupFlagLoggedInIndicatorMenu(context); } }; } return this.popupFlagLoggedInIndicatorMenuFactory; } /** * Gets the popup menu for flagging the "Logged out" pattern. * * @return the popup menu */ private PopupContextMenuItemFactory getPopupFlagLoggedOutIndicatorMenu() { if (this.popupFlagLoggedOutIndicatorMenuFactory == null) { popupFlagLoggedOutIndicatorMenuFactory = new PopupContextMenuItemFactory("dd - " + Constant.messages.getString("context.flag.popup")) { private static final long serialVersionUID = 2453839120088204123L; @Override public ExtensionPopupMenuItem getContextMenu(Context context, String parentMenu) { return new PopupFlagLoggedOutIndicatorMenu(context); } }; } return this.popupFlagLoggedOutIndicatorMenuFactory; } /** * Loads the authentication method types and hooks them up. * * @param hook the extension hook */ private void loadAuthenticationMethodTypes(ExtensionHook hook) { this.authenticationMethodTypes = new ArrayList<>(); this.authenticationMethodTypes.add(new FormBasedAuthenticationMethodType()); this.authenticationMethodTypes.add(new HttpAuthenticationMethodType()); this.authenticationMethodTypes.add(new ManualAuthenticationMethodType()); this.authenticationMethodTypes.add(new ScriptBasedAuthenticationMethodType()); for (AuthenticationMethodType a : authenticationMethodTypes) { a.hook(hook); } if (log.isInfoEnabled()) { log.info("Loaded authentication method types: " + authenticationMethodTypes); } } /** * Gets all the registered/loaded authentication method types. * * @return the authentication method types */ public List<AuthenticationMethodType> getAuthenticationMethodTypes() { return authenticationMethodTypes; } /** * Gets the authentication method type for a given identifier. * * @param id the id * @return the authentication method type for identifier */ public AuthenticationMethodType getAuthenticationMethodTypeForIdentifier(int id) { for (AuthenticationMethodType t : getAuthenticationMethodTypes()) if (t.getUniqueIdentifier() == id) return t; return null; } /** * Gets the URI for the login request that corresponds to a given context, if any. * * @param ctx the context * @return the login request uri for context, or <code>null</code>, if the context does not have * a 'login request' configured */ public URI getLoginRequestURIForContext(Context ctx) { if (!(ctx.getAuthenticationMethod() instanceof FormBasedAuthenticationMethod)) return null; FormBasedAuthenticationMethod method = (FormBasedAuthenticationMethod) ctx.getAuthenticationMethod(); try { return new URI(method.getLoginRequestURL(), false); } catch (URIException | NullPointerException e) { e.printStackTrace(); return null; } } @Override public void loadContextData(Session session, Context context) { try { List<String> typeL = session.getContextDataStrings(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_TYPE); if (typeL != null && typeL.size() > 0) { AuthenticationMethodType t = getAuthenticationMethodTypeForIdentifier(Integer.parseInt(typeL .get(0))); if (t != null) { context.setAuthenticationMethod(t.loadMethodFromSession(session, context.getIndex())); List<String> loginIndicatorL = session.getContextDataStrings(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_LOGGEDIN_INDICATOR); if (loginIndicatorL != null && loginIndicatorL.size() > 0) context.getAuthenticationMethod().setLoggedInIndicatorPattern(loginIndicatorL.get(0)); List<String> logoutIndicatorL = session.getContextDataStrings(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_LOGGEDOUT_INDICATOR); if (logoutIndicatorL != null && logoutIndicatorL.size() > 0) context.getAuthenticationMethod().setLoggedOutIndicatorPattern( logoutIndicatorL.get(0)); } } } catch (DatabaseException e) { log.error("Unable to load Authentication method.", e); } } @Override public void persistContextData(Session session, Context context) { try { AuthenticationMethodType t = context.getAuthenticationMethod().getType(); session.setContextData(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_TYPE, Integer.toString(t.getUniqueIdentifier())); if (context.getAuthenticationMethod().getLoggedInIndicatorPattern() != null) session.setContextData(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_LOGGEDIN_INDICATOR, context.getAuthenticationMethod().getLoggedInIndicatorPattern().toString()); if (context.getAuthenticationMethod().getLoggedOutIndicatorPattern() != null) session.setContextData(context.getIndex(), RecordContext.TYPE_AUTH_METHOD_LOGGEDOUT_INDICATOR, context.getAuthenticationMethod() .getLoggedOutIndicatorPattern().toString()); t.persistMethodToSession(session, context.getIndex(), context.getAuthenticationMethod()); } catch (DatabaseException e) { log.error("Unable to persist Authentication method.", e); } } @Override public void discardContexts() { contextPanelsMap.clear(); } @Override public void discardContext(Context ctx) { contextPanelsMap.remove(ctx.getIndex()); } @Override public void exportContextData(Context ctx, Configuration config) { config.setProperty(AuthenticationMethod.CONTEXT_CONFIG_AUTH_TYPE, ctx.getAuthenticationMethod().getType().getUniqueIdentifier()); if (ctx.getAuthenticationMethod().getLoggedInIndicatorPattern() != null) { config.setProperty(AuthenticationMethod.CONTEXT_CONFIG_AUTH_LOGGEDIN, ctx.getAuthenticationMethod().getLoggedInIndicatorPattern().toString()); } if (ctx.getAuthenticationMethod().getLoggedOutIndicatorPattern() != null) { config.setProperty(AuthenticationMethod.CONTEXT_CONFIG_AUTH_LOGGEDOUT, ctx.getAuthenticationMethod().getLoggedOutIndicatorPattern().toString()); } ctx.getAuthenticationMethod().getType().exportData(config, ctx.getAuthenticationMethod()); } @Override public void importContextData(Context ctx, Configuration config) throws ConfigurationException { ctx.setAuthenticationMethod( getAuthenticationMethodTypeForIdentifier( config.getInt(AuthenticationMethod.CONTEXT_CONFIG_AUTH_TYPE)).createAuthenticationMethod(ctx.getIndex())); String str = config.getString(AuthenticationMethod.CONTEXT_CONFIG_AUTH_LOGGEDIN, ""); if (str.length() > 0) { ctx.getAuthenticationMethod().setLoggedInIndicatorPattern(str); } str = config.getString(AuthenticationMethod.CONTEXT_CONFIG_AUTH_LOGGEDOUT, ""); if (str.length() > 0) { ctx.getAuthenticationMethod().setLoggedOutIndicatorPattern(str); } ctx.getAuthenticationMethod().getType().importData(config, ctx.getAuthenticationMethod()); } }