package org.owasp.webscarab.plugin.identity; import java.io.File; import java.text.ParseException; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; import org.owasp.webscarab.model.ConversationID; import org.owasp.webscarab.model.ConversationModel; import org.owasp.webscarab.model.FrameworkModel; import org.owasp.webscarab.model.HttpUrl; import org.owasp.webscarab.model.NamedValue; import org.owasp.webscarab.model.Request; import org.owasp.webscarab.model.Response; import org.owasp.webscarab.model.StoreException; import org.owasp.webscarab.plugin.Framework; import org.owasp.webscarab.plugin.Hook; import org.owasp.webscarab.plugin.Plugin; import org.owasp.webscarab.util.RFC2822; public class Identity implements Plugin { private Framework framework; private IdentityModel model; private List<TokenParser> tokenParsers = new LinkedList<TokenParser>(); public Identity(Framework framework) { this.framework = framework; model = new IdentityModel(framework.getModel()); tokenParsers.add(new CookieTokenParser()); } public Framework getFramework() { return framework; } public void removeTransitions() { model.removeTransitions(); } public void addTransition(ConversationID conversation, String tokenName, String tokenValue, String identity) { Date date = getConversationDate(conversation); Transition transition = new Transition(conversation, date, tokenName, tokenValue, identity); model.addTransition(transition); SortedMap<ConversationID, Transition> transitions = model.getTransitions(tokenName, tokenValue); ConversationID next = null; Iterator<ConversationID> it = transitions.keySet().iterator(); while (it.hasNext()) { if (it.next().equals(conversation)) { if (it.hasNext()) next = it.next(); break; } } ConversationModel cm = framework.getModel().getConversationModel(); int c = cm.getConversationCount(); if (next == null) next = cm.getConversationAt(c - 1); for (int i = 0; i < c; i++) { ConversationID id = cm.getConversationAt(i); if (id.compareTo(conversation) >= 0) { // FIXME: When removing the identity, this should only take effect from the NEXT request. List<NamedValue> tokens = getRequestTokens(cm.getRequest(id)); tokens.addAll(getResponseTokens(cm.getResponse(id))); for (NamedValue token : tokens) { if (token.getName().equals(tokenName) && token.getValue().equals(tokenValue)) { cm.setConversationProperty(id, "IDENTITY", identity); break; } } } } } public List<String> getIdentities() { return model.getIdentities(); } public String getIdentity(ConversationID conversation, NamedValue token) { Transition transition = model.getIdentity(conversation, token.getName(), token.getValue()); if (transition == null) return null; return transition.getIdentity(); } public List<String> getIdentities(ConversationID conversation) { List<NamedValue> tokens = getRequestTokens(framework.getModel() .getRequest(conversation)); List<String> identities = new LinkedList<String>(); if (tokens == null) return null; for (NamedValue token : tokens) { Transition transition = model.getIdentity(conversation, token.getName(), token.getValue()); if (transition == null) continue; identities.add(transition.getIdentity()); } return identities.size() == 0 ? null : identities; } private Date getConversationDate(ConversationID id) { Response response = framework.getModel().getResponse(id); Date date = null; String serverTime = response.getHeader("Date"); if (serverTime != null) { try { date = RFC2822.parseDate(serverTime); } catch (ParseException e) { } } if (date == null) date = framework.getModel().getConversationDate(id); return date; } public List<NamedValue> getRequestTokens(Request request) { List<NamedValue> tokens = new LinkedList<NamedValue>(); for (TokenParser parser : tokenParsers) { List<NamedValue> list = parser.getTokens(request); if (list != null) tokens.addAll(list); } return tokens; } public List<NamedValue> getResponseTokens(Response response) { List<NamedValue> tokens = new LinkedList<NamedValue>(); for (TokenParser parser : tokenParsers) { List<NamedValue> list = parser.getTokens(response); if (list != null) tokens.addAll(list); } return tokens; } @Override public String getPluginName() { return "Identity"; } @Override public void setSession(String type, Object store, String session) throws StoreException { if (type.equals("FileSystem") && (store instanceof File)) { model.setStore(new FileSystemStore((File) store, session)); } else { throw new StoreException("Store type '" + type + "' is not supported in " + getClass().getName()); } } @Override public void run() { model.setRunning(true); try { Thread.sleep(2000); } catch (InterruptedException ie) {} FrameworkModel fm = framework.getModel(); ConversationModel cm = fm.getConversationModel(); int c = cm.getConversationCount(); for (int i=0; i < c; i++) { ConversationID cid = cm.getConversationAt(i); Request req = cm.getRequest(cid); HttpUrl url = req.getURL(); List<NamedValue> tokens = getRequestTokens(req); if (url.toString().endsWith("logout.php")) { String sessid = tokens.get(0).getValue(); addTransition(cid, "PHPSESSID", sessid, null); } else if (req.getMethod().equals("POST") && url.toString().endsWith("login.php")) { String sessid = null; if (tokens.size() > 0) sessid = tokens.get(0).getValue(); Response response = cm.getResponse(cid); if (response.getStatus().equals("302")) { String who = null; tokens = getResponseTokens(response); if (tokens.size() > 0) sessid = tokens.get(0).getValue(); String content = new String(req.getContent()); NamedValue[] params = NamedValue.splitNamedValues(content, "&", "="); for (int j = 0; j<params.length; j++) if (params[j].getName().equals("user")) who = params[j].getValue(); addTransition(cid, "PHPSESSID", sessid, who); } } } } @Override public boolean isRunning() { return model.isRunning(); } @Override public boolean isBusy() { return model.isBusy(); } @Override public String getStatus() { return model.getStatus(); } @Override public boolean stop() { model.setRunning(false); return !model.isRunning(); } @Override public boolean isModified() { return model.isModified(); } @Override public void flush() throws StoreException { // TODO Auto-generated method stub } @Override public void analyse(ConversationID id, Request request, Response response, String origin) { // TODO Auto-generated method stub } @Override public Hook[] getScriptingHooks() { return null; } @Override public Object getScriptableObject() { return null; } private static Identity identity; }