/***********************************************************************
*
* $CVSHeader$
*
* This file is part of WebScarab, an Open Web Application Security
* Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2011 FedICT
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source
* ==============
*
* Source for this application is maintained at Sourceforge.net, a
* repository for free software projects.
*
* For details, please see http://www.sourceforge.net/projects/owasp
*
*/
package org.owasp.webscarab.plugin.wsfed;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xml.security.utils.Constants;
import org.apache.xpath.XPathAPI;
import org.owasp.webscarab.model.ConversationID;
import org.owasp.webscarab.model.ConversationModel;
import org.owasp.webscarab.model.FilteredConversationModel;
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.plugin.AbstractPluginModel;
import org.owasp.webscarab.util.Encoding;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
*
* @author Frank Cornelis
*/
public class WSFederationModel extends AbstractPluginModel {
private final FrameworkModel model;
private final ConversationModel wsfedConversationModel;
public WSFederationModel(FrameworkModel model) {
this.model = model;
this.wsfedConversationModel = new FilteredConversationModel(model, model.getConversationModel()) {
@Override
public boolean shouldFilter(ConversationID id) {
return !isWSFederationMessage(id);
}
};
}
private boolean isWSFederationMessage(ConversationID id) {
if (null != this.model.getConversationProperty(id, "WTREALM")) {
return true;
}
if (null != this.model.getConversationProperty(id, "WRESULT")) {
return true;
}
return false;
}
public ConversationModel getConversationModel() {
return this.wsfedConversationModel;
}
public void setSignInRequestMessage(ConversationID id, String wtrealm) {
this.model.setConversationProperty(id, "WTREALM", wtrealm);
}
public void setSignInResponseMessage(ConversationID id, String wresult) {
this.model.setConversationProperty(id, "WRESULT", wresult);
}
public String getReadableMessageType(ConversationID conversationId) {
if (null != this.model.getConversationProperty(conversationId, "WTREALM")) {
return "Sign-In Request";
}
if (null != this.model.getConversationProperty(conversationId, "WRESULT")) {
return "Sign-In Response";
}
return "Unknown";
}
public List getParameters(ConversationID id) {
NamedValue[] values = null;
Request request = this.model.getRequest(id);
String method = request.getMethod();
if (method.equals("GET")) {
HttpUrl url = request.getURL();
String query = url.getQuery();
if (null != query) {
values = NamedValue.splitNamedValues(query, "&", "=");
}
} else if (method.equals("POST")) {
byte[] requestContent = request.getContent();
if (requestContent != null && requestContent.length > 0) {
String body = new String(requestContent);
values = NamedValue.splitNamedValues(
body, "&", "=");
}
}
if (null == values) {
return Collections.emptyList();
}
for (int idx = 0; idx < values.length; idx++) {
NamedValue namedValue = values[idx];
String name = namedValue.getName();
String value = Encoding.urlDecode(namedValue.getValue());
namedValue = new NamedValue(name, value);
values[idx] = namedValue;
}
return Arrays.asList(values);
}
public byte[] findSAMLAssertion(byte[] wresult) throws ParserConfigurationException, SAXException, IOException, TransformerException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(wresult);
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(inputStream);
Element nsElement = document.createElement("nsElement");
nsElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:saml2",
"urn:oasis:names:tc:SAML:2.0:assertion");
Node assertionNode = XPathAPI.selectSingleNode(document, "//saml2:Assertion", nsElement);
if (null == assertionNode) {
return null;
}
Source source = new DOMSource(assertionNode);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Result result = new StreamResult(outputStream);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(source, result);
return outputStream.toByteArray();
}
public List getSAMLAttributes(byte[] assertion) throws ParserConfigurationException, SAXException, IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(assertion);
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(inputStream);
List samlAttributes = new ArrayList();
NodeList attribute2NodeList = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "Attribute");
for (int idx = 0; idx < attribute2NodeList.getLength(); idx++) {
Element attributeElement = (Element) attribute2NodeList.item(idx);
String attributeName = attributeElement.getAttribute("Name");
NodeList attributeValueNodeList = attributeElement.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "AttributeValue");
if (0 == attributeValueNodeList.getLength()) {
continue;
}
Element attributeValueElement = (Element) attributeValueNodeList.item(0);
String attributeValue = attributeValueElement.getChildNodes().item(0).getNodeValue();
NamedValue attribute = new NamedValue(attributeName, attributeValue);
samlAttributes.add(attribute);
}
return samlAttributes;
}
}