KEYCLOAK-3864 Add support for SAML2 <Extensions> element in protocol messages

This commit is contained in:
Hynek Mlnarik 2016-11-01 13:39:14 +01:00
parent 6baf9b89fe
commit 904a5c3ca5
25 changed files with 539 additions and 5 deletions

View file

@ -53,6 +53,18 @@
<groupId>org.apache.santuario</groupId> <groupId>org.apache.santuario</groupId>
<artifactId>xmlsec</artifactId> <artifactId>xmlsec</artifactId>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
<resources> <resources>

View file

@ -25,15 +25,19 @@ import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.net.URI; import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
/** /**
* @author pedroigor * @author pedroigor
*/ */
public class SAML2AuthnRequestBuilder { public class SAML2AuthnRequestBuilder implements SamlProtocolExtensionsAwareBuilder<SAML2AuthnRequestBuilder> {
private final AuthnRequestType authnRequestType; private final AuthnRequestType authnRequestType;
protected String destination; protected String destination;
protected String issuer; protected String issuer;
protected final List<NodeGenerator> extensions = new LinkedList<>();
public SAML2AuthnRequestBuilder destination(String destination) { public SAML2AuthnRequestBuilder destination(String destination) {
this.destination = destination; this.destination = destination;
@ -45,6 +49,12 @@ public class SAML2AuthnRequestBuilder {
return this; return this;
} }
@Override
public SAML2AuthnRequestBuilder addExtension(NodeGenerator extension) {
this.extensions.add(extension);
return this;
}
public SAML2AuthnRequestBuilder() { public SAML2AuthnRequestBuilder() {
try { try {
this.authnRequestType = new AuthnRequestType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant()); this.authnRequestType = new AuthnRequestType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());
@ -90,6 +100,14 @@ public class SAML2AuthnRequestBuilder {
authnRequestType.setDestination(URI.create(this.destination)); authnRequestType.setDestination(URI.create(this.destination));
if (! this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
authnRequestType.setExtensions(extensionsType);
}
return new SAML2Request().convert(authnRequestType); return new SAML2Request().convert(authnRequestType);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Could not convert " + authnRequestType + " to a document.", e); throw new RuntimeException("Could not convert " + authnRequestType + " to a document.", e);

View file

@ -17,7 +17,10 @@
package org.keycloak.saml; package org.keycloak.saml;
import java.util.LinkedList;
import java.util.List;
import org.keycloak.dom.saml.v2.assertion.NameIDType; import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import org.keycloak.dom.saml.v2.protocol.StatusResponseType; import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
import org.keycloak.saml.common.exceptions.ConfigurationException; import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException; import org.keycloak.saml.common.exceptions.ParsingException;
@ -32,11 +35,12 @@ import org.w3c.dom.Document;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SAML2ErrorResponseBuilder { public class SAML2ErrorResponseBuilder implements SamlProtocolExtensionsAwareBuilder<SAML2ErrorResponseBuilder> {
protected String status; protected String status;
protected String destination; protected String destination;
protected String issuer; protected String issuer;
protected final List<NodeGenerator> extensions = new LinkedList<>();
public SAML2ErrorResponseBuilder status(String status) { public SAML2ErrorResponseBuilder status(String status) {
this.status = status; this.status = status;
@ -53,6 +57,11 @@ public class SAML2ErrorResponseBuilder {
return this; return this;
} }
@Override
public SAML2ErrorResponseBuilder addExtension(NodeGenerator extension) {
this.extensions.add(extension);
return this;
}
public Document buildDocument() throws ProcessingException { public Document buildDocument() throws ProcessingException {
@ -66,6 +75,14 @@ public class SAML2ErrorResponseBuilder {
statusResponse.setIssuer(issuer); statusResponse.setIssuer(issuer);
statusResponse.setDestination(destination); statusResponse.setDestination(destination);
if (! this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
statusResponse.setExtensions(extensionsType);
}
SAML2Response saml2Response = new SAML2Response(); SAML2Response saml2Response = new SAML2Response();
return saml2Response.convert(statusResponse); return saml2Response.convert(statusResponse);
} catch (ConfigurationException e) { } catch (ConfigurationException e) {

View file

@ -39,6 +39,9 @@ import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.net.URI; import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import static org.keycloak.saml.common.util.StringUtil.isNotNull; import static org.keycloak.saml.common.util.StringUtil.isNotNull;
@ -49,7 +52,7 @@ import static org.keycloak.saml.common.util.StringUtil.isNotNull;
* *
* @author bburke@redhat.com * @author bburke@redhat.com
*/ */
public class SAML2LoginResponseBuilder { public class SAML2LoginResponseBuilder implements SamlProtocolExtensionsAwareBuilder<SAML2LoginResponseBuilder> {
protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
protected String destination; protected String destination;
@ -64,6 +67,7 @@ public class SAML2LoginResponseBuilder {
protected String authMethod; protected String authMethod;
protected String requestIssuer; protected String requestIssuer;
protected String sessionIndex; protected String sessionIndex;
protected final List<NodeGenerator> extensions = new LinkedList<>();
public SAML2LoginResponseBuilder sessionIndex(String sessionIndex) { public SAML2LoginResponseBuilder sessionIndex(String sessionIndex) {
@ -136,6 +140,12 @@ public class SAML2LoginResponseBuilder {
return this; return this;
} }
@Override
public SAML2LoginResponseBuilder addExtension(NodeGenerator extension) {
this.extensions.add(extension);
return this;
}
public Document buildDocument(ResponseType responseType) throws ConfigurationException, ProcessingException { public Document buildDocument(ResponseType responseType) throws ConfigurationException, ProcessingException {
Document samlResponseDocument = null; Document samlResponseDocument = null;
@ -207,6 +217,14 @@ public class SAML2LoginResponseBuilder {
assertion.addStatement(authnStatement); assertion.addStatement(authnStatement);
} }
if (! this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
responseType.setExtensions(extensionsType);
}
return responseType; return responseType;
} }

View file

@ -27,18 +27,22 @@ import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.net.URI; import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SAML2LogoutRequestBuilder { public class SAML2LogoutRequestBuilder implements SamlProtocolExtensionsAwareBuilder<SAML2LogoutRequestBuilder> {
protected String userPrincipal; protected String userPrincipal;
protected String userPrincipalFormat; protected String userPrincipalFormat;
protected String sessionIndex; protected String sessionIndex;
protected long assertionExpiration; protected long assertionExpiration;
protected String destination; protected String destination;
protected String issuer; protected String issuer;
protected final List<NodeGenerator> extensions = new LinkedList<>();
public SAML2LogoutRequestBuilder destination(String destination) { public SAML2LogoutRequestBuilder destination(String destination) {
this.destination = destination; this.destination = destination;
@ -50,6 +54,12 @@ public class SAML2LogoutRequestBuilder {
return this; return this;
} }
@Override
public SAML2LogoutRequestBuilder addExtension(NodeGenerator extension) {
this.extensions.add(extension);
return this;
}
/** /**
* Length of time in seconds the assertion is valid for * Length of time in seconds the assertion is valid for
* See SAML core specification 2.5.1.2 NotOnOrAfter * See SAML core specification 2.5.1.2 NotOnOrAfter
@ -99,6 +109,15 @@ public class SAML2LogoutRequestBuilder {
if (assertionExpiration > 0) lort.setNotOnOrAfter(XMLTimeUtil.add(lort.getIssueInstant(), assertionExpiration * 1000)); if (assertionExpiration > 0) lort.setNotOnOrAfter(XMLTimeUtil.add(lort.getIssueInstant(), assertionExpiration * 1000));
lort.setDestination(URI.create(destination)); lort.setDestination(URI.create(destination));
if (! this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
lort.setExtensions(extensionsType);
}
return lort; return lort;
} }
} }

View file

@ -31,16 +31,20 @@ import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.net.URI; import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SAML2LogoutResponseBuilder { public class SAML2LogoutResponseBuilder implements SamlProtocolExtensionsAwareBuilder<SAML2LogoutResponseBuilder> {
protected String logoutRequestID; protected String logoutRequestID;
protected String destination; protected String destination;
protected String issuer; protected String issuer;
protected final List<NodeGenerator> extensions = new LinkedList<>();
public SAML2LogoutResponseBuilder logoutRequestID(String logoutRequestID) { public SAML2LogoutResponseBuilder logoutRequestID(String logoutRequestID) {
this.logoutRequestID = logoutRequestID; this.logoutRequestID = logoutRequestID;
@ -57,6 +61,11 @@ public class SAML2LogoutResponseBuilder {
return this; return this;
} }
@Override
public SAML2LogoutResponseBuilder addExtension(NodeGenerator extension) {
this.extensions.add(extension);
return this;
}
public Document buildDocument() throws ProcessingException { public Document buildDocument() throws ProcessingException {
Document samlResponse = null; Document samlResponse = null;
@ -77,6 +86,14 @@ public class SAML2LogoutResponseBuilder {
statusResponse.setIssuer(issuer); statusResponse.setIssuer(issuer);
statusResponse.setDestination(destination); statusResponse.setDestination(destination);
if (! this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
statusResponse.setExtensions(extensionsType);
}
SAML2Response saml2Response = new SAML2Response(); SAML2Response saml2Response = new SAML2Response();
samlResponse = saml2Response.convert(statusResponse); samlResponse = saml2Response.convert(statusResponse);
} catch (ConfigurationException e) { } catch (ConfigurationException e) {

View file

@ -0,0 +1,49 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.saml;
import javax.xml.stream.XMLStreamWriter;
import org.keycloak.saml.common.exceptions.ProcessingException;
/**
* Implementations of this interface are builders that can register &lt;samlp:Extensions&gt;
* content providers.
*
* @author hmlnarik
*/
public interface SamlProtocolExtensionsAwareBuilder<T> {
public interface NodeGenerator {
/**
* Generate contents of the &lt;samlp:Extensions&gt; tag. When this method is invoked,
* the writer has already emitted the &lt;samlp:Extensions&gt; start tag.
*
* @param writer Writer to use for producing XML output
* @throws ProcessingException If any exception fails
*/
void write(XMLStreamWriter writer) throws ProcessingException;
}
/**
* Adds a given node subtree as a SAML protocol extension into the SAML protocol message.
*
* @param extension
* @return
*/
T addExtension(NodeGenerator extension);
}

View file

@ -450,6 +450,11 @@ public class DefaultPicketLinkLogger implements PicketLinkLogger {
return new RuntimeException(ErrorCodes.EXPECTED_TAG + tag + ">. Found <" + foundElementTag + ">"); return new RuntimeException(ErrorCodes.EXPECTED_TAG + tag + ">. Found <" + foundElementTag + ">");
} }
@Override
public RuntimeException parserExpectedNamespace(String ns, String foundElementNs) {
return new RuntimeException(ErrorCodes.EXPECTED_NAMESPACE + ns + ">. Found <" + foundElementNs + ">");
}
/* /*
*(non-Javadoc) *(non-Javadoc)
* *
@ -2378,4 +2383,10 @@ public class DefaultPicketLinkLogger implements PicketLinkLogger {
return new ProcessingException("Wrong audience [" + serviceURL + "]."); return new ProcessingException("Wrong audience [" + serviceURL + "].");
} }
@Override
public ProcessingException samlExtensionUnknownChild(Class<?> clazz) {
return new ProcessingException("Unknown child type specified for extension: "
+ (clazz == null ? "<null>" : clazz.getSimpleName())
+ ".");
}
} }

View file

@ -48,6 +48,8 @@ public interface ErrorCodes {
String EXPECTED_TAG = "PL00066: Parser : Expected start tag:"; String EXPECTED_TAG = "PL00066: Parser : Expected start tag:";
String EXPECTED_NAMESPACE = "PL00107: Parser : Expected start element namespace:";
String EXPECTED_TEXT_VALUE = "PL00071: Parser: Expected text value:"; String EXPECTED_TEXT_VALUE = "PL00071: Parser: Expected text value:";
String EXPECTED_END_TAG = "PL00066: Parser : Expected end tag:"; String EXPECTED_END_TAG = "PL00066: Parser : Expected end tag:";

View file

@ -296,6 +296,14 @@ public interface PicketLinkLogger {
*/ */
RuntimeException parserExpectedTag(String tag, String foundElementTag); RuntimeException parserExpectedTag(String tag, String foundElementTag);
/**
* @param ns
* @param foundElementNs
*
* @return
*/
RuntimeException parserExpectedNamespace(String ns, String foundElementNs);
/** /**
* @param elementName * @param elementName
* *
@ -1219,4 +1227,6 @@ public interface PicketLinkLogger {
RuntimeException parserFeatureNotSupported(String feature); RuntimeException parserFeatureNotSupported(String feature);
ProcessingException samlAssertionWrongAudience(String serviceURL); ProcessingException samlAssertionWrongAudience(String serviceURL);
ProcessingException samlExtensionUnknownChild(Class<?> clazz);
} }

View file

@ -58,6 +58,8 @@ public class SAMLArtifactResolveParser extends SAMLRequestAbstractParser impleme
continue; continue;
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
continue; continue;
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
continue;
} else } else
throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location=" throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location="
+ startElement.getLocation()); + startElement.getLocation());

View file

@ -68,6 +68,9 @@ public class SAMLArtifactResponseParser extends SAMLStatusResponseTypeParser imp
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
Element sig = StaxParserUtil.getDOMElement(xmlEventReader); Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
response.setSignature(sig); response.setSignature(sig);
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
SAMLExtensionsParser extensionsParser = new SAMLExtensionsParser();
response.setExtensions(extensionsParser.parse(xmlEventReader));
} else if (JBossSAMLConstants.AUTHN_REQUEST.get().equals(elementName)) { } else if (JBossSAMLConstants.AUTHN_REQUEST.get().equals(elementName)) {
SAMLAuthNRequestParser authnParser = new SAMLAuthNRequestParser(); SAMLAuthNRequestParser authnParser = new SAMLAuthNRequestParser();
AuthnRequestType authn = (AuthnRequestType) authnParser.parse(xmlEventReader); AuthnRequestType authn = (AuthnRequestType) authnParser.parse(xmlEventReader);

View file

@ -60,6 +60,8 @@ public class SAMLAttributeQueryParser extends SAMLRequestAbstractParser implemen
continue; continue;
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
continue; continue;
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
continue;
} else } else
throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location=" throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location="
+ startElement.getLocation()); + startElement.getLocation());

View file

@ -76,6 +76,8 @@ public class SAMLAuthNRequestParser extends SAMLRequestAbstractParser implements
continue; continue;
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
continue; continue;
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
continue;
} else } else
throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location=" throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location="
+ startElement.getLocation()); + startElement.getLocation());

View file

@ -0,0 +1,82 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.saml.processing.core.parsers.saml;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import org.keycloak.saml.common.PicketLinkLogger;
import org.keycloak.saml.common.PicketLinkLoggerFactory;
import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.ParserNamespaceSupport;
import org.keycloak.saml.common.util.StaxParserUtil;
/**
* Parses &lt;samlp:Extensions&gt; SAML2 element into series of DOM nodes.
*
* @author hmlnarik
*/
public class SAMLExtensionsParser implements ParserNamespaceSupport {
private static final String EXTENSIONS = JBossSAMLConstants.EXTENSIONS.get();
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
@Override
public ExtensionsType parse(XMLEventReader xmlEventReader) throws ParsingException {
// Get the startelement
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, EXTENSIONS);
ExtensionsType extensions = new ExtensionsType();
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent instanceof EndElement) {
EndElement endElement = (EndElement) xmlEvent;
if (StaxParserUtil.matches(endElement, EXTENSIONS)) {
endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
break;
} else
throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
extensions.addExtension(StaxParserUtil.getDOMElement(xmlEventReader));
}
return extensions;
}
@Override
public boolean supports(QName qname) {
String nsURI = qname.getNamespaceURI();
String localPart = qname.getLocalPart();
return nsURI.equals(JBossSAMLURIConstants.PROTOCOL_NSURI.get())
&& localPart.equals(JBossSAMLConstants.EXTENSIONS.get());
}
}

View file

@ -71,6 +71,9 @@ public class SAMLResponseParser extends SAMLStatusResponseTypeParser implements
} else if (JBossSAMLConstants.ASSERTION.get().equals(elementName)) { } else if (JBossSAMLConstants.ASSERTION.get().equals(elementName)) {
SAMLAssertionParser assertionParser = new SAMLAssertionParser(); SAMLAssertionParser assertionParser = new SAMLAssertionParser();
response.addAssertion(new RTChoiceType((AssertionType) assertionParser.parse(xmlEventReader))); response.addAssertion(new RTChoiceType((AssertionType) assertionParser.parse(xmlEventReader)));
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
SAMLExtensionsParser extensionsParser = new SAMLExtensionsParser();
response.setExtensions(extensionsParser.parse(xmlEventReader));
} else if (JBossSAMLConstants.STATUS.get().equals(elementName)) { } else if (JBossSAMLConstants.STATUS.get().equals(elementName)) {
response.setStatus(parseStatus(xmlEventReader)); response.setStatus(parseStatus(xmlEventReader));
} else if (JBossSAMLConstants.ENCRYPTED_ASSERTION.get().equals(elementName)) { } else if (JBossSAMLConstants.ENCRYPTED_ASSERTION.get().equals(elementName)) {

View file

@ -74,6 +74,8 @@ public class SAMLSloRequestParser extends SAMLRequestAbstractParser implements P
continue; continue;
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
continue; continue;
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
continue;
} else } else
throw logger.parserUnknownTag(elementName, startElement.getLocation()); throw logger.parserUnknownTag(elementName, startElement.getLocation());
} }

View file

@ -60,6 +60,9 @@ public class SAMLSloResponseParser extends SAMLStatusResponseTypeParser implemen
} else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) { } else if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.bypassElementBlock(xmlEventReader, JBossSAMLConstants.SIGNATURE.get()); StaxParserUtil.bypassElementBlock(xmlEventReader, JBossSAMLConstants.SIGNATURE.get());
} else if (JBossSAMLConstants.EXTENSIONS.get().equals(elementName)) {
SAMLExtensionsParser extensionsParser = new SAMLExtensionsParser();
response.setExtensions(extensionsParser.parse(xmlEventReader));
} else if (JBossSAMLConstants.STATUS.get().equals(elementName)) { } else if (JBossSAMLConstants.STATUS.get().equals(elementName)) {
response.setStatus(parseStatus(xmlEventReader)); response.setStatus(parseStatus(xmlEventReader));
} }

View file

@ -43,8 +43,12 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import org.keycloak.saml.SamlProtocolExtensionsAwareBuilder;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI; import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI;
import org.w3c.dom.Node;
/** /**
* Base Class for the Stax writers for SAML * Base Class for the Stax writers for SAML
@ -244,6 +248,28 @@ public class BaseWriter {
StaxUtil.flush(writer); StaxUtil.flush(writer);
} }
public void write(ExtensionsType extensions) throws ProcessingException {
if (extensions.getAny().isEmpty()) {
return;
}
StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.EXTENSIONS.get(), PROTOCOL_NSURI.get());
for (Object o : extensions.getAny()) {
if (o instanceof Node) {
StaxUtil.writeDOMNode(writer, (Node) o);
} else if (o instanceof SamlProtocolExtensionsAwareBuilder.NodeGenerator) {
SamlProtocolExtensionsAwareBuilder.NodeGenerator ng = (SamlProtocolExtensionsAwareBuilder.NodeGenerator) o;
ng.write(writer);
} else {
throw logger.samlExtensionUnknownChild(o == null ? null : o.getClass());
}
}
StaxUtil.writeEndElement(writer);
StaxUtil.flush(writer);
}
private void write(SubjectConfirmationType subjectConfirmationType) throws ProcessingException { private void write(SubjectConfirmationType subjectConfirmationType) throws ProcessingException {
StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.SUBJECT_CONFIRMATION.get(), StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.SUBJECT_CONFIRMATION.get(),
ASSERTION_NSURI.get()); ASSERTION_NSURI.get());

View file

@ -36,6 +36,7 @@ import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI; import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI; import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI;
@ -122,6 +123,11 @@ public class SAMLRequestWriter extends BaseWriter {
StaxUtil.writeDOMElement(writer, sig); StaxUtil.writeDOMElement(writer, sig);
} }
ExtensionsType extensions = request.getExtensions();
if (extensions != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
NameIDPolicyType nameIDPolicy = request.getNameIDPolicy(); NameIDPolicyType nameIDPolicy = request.getNameIDPolicy();
if (nameIDPolicy != null) { if (nameIDPolicy != null) {
write(nameIDPolicy); write(nameIDPolicy);
@ -171,6 +177,11 @@ public class SAMLRequestWriter extends BaseWriter {
StaxUtil.writeDOMElement(writer, signature); StaxUtil.writeDOMElement(writer, signature);
} }
ExtensionsType extensions = logOutRequest.getExtensions();
if (extensions != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
NameIDType nameID = logOutRequest.getNameID(); NameIDType nameID = logOutRequest.getNameID();
if (nameID != null) { if (nameID != null) {
write(nameID, new QName(ASSERTION_NSURI.get(), JBossSAMLConstants.NAMEID.get(), ASSERTION_PREFIX)); write(nameID, new QName(ASSERTION_NSURI.get(), JBossSAMLConstants.NAMEID.get(), ASSERTION_PREFIX));
@ -278,6 +289,11 @@ public class SAMLRequestWriter extends BaseWriter {
if (sig != null) { if (sig != null) {
StaxUtil.writeDOMElement(writer, sig); StaxUtil.writeDOMElement(writer, sig);
} }
ExtensionsType extensions = request.getExtensions();
if (extensions != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
String artifact = request.getArtifact(); String artifact = request.getArtifact();
if (StringUtil.isNotNull(artifact)) { if (StringUtil.isNotNull(artifact)) {
StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.ARTIFACT.get(), PROTOCOL_NSURI.get()); StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.ARTIFACT.get(), PROTOCOL_NSURI.get());
@ -315,6 +331,10 @@ public class SAMLRequestWriter extends BaseWriter {
if (sig != null) { if (sig != null) {
StaxUtil.writeDOMElement(writer, sig); StaxUtil.writeDOMElement(writer, sig);
} }
ExtensionsType extensions = request.getExtensions();
if (extensions != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
SubjectType subject = request.getSubject(); SubjectType subject = request.getSubject();
if (subject != null) { if (subject != null) {
write(subject); write(subject);

View file

@ -37,6 +37,7 @@ import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
/** /**
* Write a SAML Response to stream * Write a SAML Response to stream
@ -78,6 +79,10 @@ public class SAMLResponseWriter extends BaseWriter {
if (sig != null) { if (sig != null) {
StaxUtil.writeDOMElement(writer, sig); StaxUtil.writeDOMElement(writer, sig);
} }
ExtensionsType extensions = response.getExtensions();
if (extensions != null && extensions.getAny() != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
StatusType status = response.getStatus(); StatusType status = response.getStatus();
write(status); write(status);
@ -119,6 +124,10 @@ public class SAMLResponseWriter extends BaseWriter {
if (sig != null) { if (sig != null) {
StaxUtil.writeDOMElement(writer, sig); StaxUtil.writeDOMElement(writer, sig);
} }
ExtensionsType extensions = response.getExtensions();
if (extensions != null && extensions.getAny() != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
StatusType status = response.getStatus(); StatusType status = response.getStatus();
if (status != null) { if (status != null) {
@ -163,6 +172,15 @@ public class SAMLResponseWriter extends BaseWriter {
NameIDType issuer = response.getIssuer(); NameIDType issuer = response.getIssuer();
write(issuer, new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(), JBossSAMLConstants.ISSUER.get(), ASSERTION_PREFIX)); write(issuer, new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(), JBossSAMLConstants.ISSUER.get(), ASSERTION_PREFIX));
Element sig = response.getSignature();
if (sig != null) {
StaxUtil.writeDOMElement(writer, sig);
}
ExtensionsType extensions = response.getExtensions();
if (extensions != null && extensions.getAny() != null && ! extensions.getAny().isEmpty()) {
write(extensions);
}
StatusType status = response.getStatus(); StatusType status = response.getStatus();
write(status); write(status);

View file

@ -0,0 +1,107 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.saml.processing.core.parsers.saml;
import java.io.InputStream;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
import org.w3c.dom.Element;
/**
* Test class for SAML parser.
*
* TODO: Add further tests.
*
* @author hmlnarik
*/
public class SAMLParserTest {
@Test
public void testSaml20EncryptedAssertionsSignedReceivedWithRedirectBinding() throws Exception {
InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response.xml");
SAMLParser parser = new SAMLParser();
Object parsedObject = parser.parse(st);
assertThat(parsedObject, instanceOf(ResponseType.class));
ResponseType resp = (ResponseType) parsedObject;
assertThat(resp.getSignature(), nullValue());
assertThat(resp.getConsent(), nullValue());
assertThat(resp.getIssuer(), not(nullValue()));
assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
assertThat(resp.getExtensions(), not(nullValue()));
assertThat(resp.getExtensions().getAny().size(), is(1));
assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
Element el = (Element) resp.getExtensions().getAny().get(0);
assertThat(el.getLocalName(), is("KeyInfo"));
assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
assertThat(resp.getAssertions(), not(nullValue()));
assertThat(resp.getAssertions().size(), is(1));
}
@Test
public void testSaml20EncryptedAssertionsSignedTwoExtensionsReceivedWithRedirectBinding() throws Exception {
Element el;
InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response-two-extensions.xml");
SAMLParser parser = new SAMLParser();
Object parsedObject = parser.parse(st);
assertThat(parsedObject, instanceOf(ResponseType.class));
ResponseType resp = (ResponseType) parsedObject;
assertThat(resp.getSignature(), nullValue());
assertThat(resp.getConsent(), nullValue());
assertThat(resp.getIssuer(), not(nullValue()));
assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
assertThat(resp.getExtensions(), not(nullValue()));
assertThat(resp.getExtensions().getAny().size(), is(2));
assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
el = (Element) resp.getExtensions().getAny().get(0);
assertThat(el.getLocalName(), is("KeyInfo"));
assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
assertThat(resp.getExtensions().getAny().get(1), instanceOf(Element.class));
el = (Element) resp.getExtensions().getAny().get(1);
assertThat(el.getLocalName(), is("ever"));
assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:what:1.0"));
assertThat(el.hasAttribute("what"), is(true));
assertThat(el.getAttribute("what"), is("ever"));
assertThat(resp.getAssertions(), not(nullValue()));
assertThat(resp.getAssertions().size(), is(1));
}
@Test
public void testSaml20PostLogoutRequest() throws Exception {
InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml");
SAMLParser parser = new SAMLParser();
Object parsedObject = parser.parse(st);
assertThat(parsedObject, instanceOf(LogoutRequestType.class));
}
}

View file

@ -0,0 +1,30 @@
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8080/sales-post-enc/saml" ID="ID_0b43d444-d1a8-44a5-8caf-38e176489e1f" InResponseTo="ID_223d3591-22fb-4b3c-9e38-4719293b2d94" IssueInstant="2016-11-01T13:52:43.054Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8081/auth/realms/saml-demo</saml:Issuer>
<samlp:Extensions>
<kckey:KeyInfo xmlns:kckey="urn:keycloak:ext:key:1.0" MessageSigningKeyId="FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"/>
<what:ever xmlns:what="urn:keycloak:ext:what:1.0" what="ever"/>
</samlp:Extensions>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<xenc:CipherData>
<xenc:CipherValue>
OkvZTx/ifYLef74rY0F9I8lbJaatgSEguo+zwh5JrYWcO09Ib2gtz5+z+67Is2+wk/OzKp154r8qAI5vY9AYvuXCslKL/wbcZ1UILL78F0T/iiUW3VpWy8Wvz5nezBFPRqot8WiFQykByjlBg1Z8XOts+uIdyqBBi/WjYeJGMaQ=
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>
RW2eu9nP2Ez9hfRlug9xC+kFfVF3HZpEb4kIFH33gmVbzrQjPk0l67uXkwRjC82FZZ482QnHCBIqNFlAryds/zTa6wdRvFmhQnIM6WxoAl8TM+e9h8MoKkalMc8J/Qfp+WQ7/XdmCg2pp9VvUZTK+g0+G4aGuL+S5+ssZq4rl9k7LrSYyp6vj+djgvISZiz5hPYJCN/WY/gWXfVuLHSpu4CmZt8D2APtT3ax1WmGcuzStAfTW8q3MFIDNV59hkpFmDb+gvyLNbZ95cDYxofiPXaC5cOTftnSBp68Ay1eienqdttEDo4fyakszdvq128KwXkH9azCg6sqLxli6B8l2xdq41MeuJO54VqmOhhLxwKy42NtnJvK/NkNwttH4yMwDPpPbC4vOKCXxT2r2F7jjvJQNB2VFv+oiUAWSSc3fGQcc2uNlx9YQVuzTmjqc7fXAWCGgYoogC8AeNWni204bnBoVpFrEo3gzuOe2fFsddJIclglmTH1hWf31FXUHDO2nl/lT4puQVTo+I+d6jpiV+qdp823NDntRxljRlUJO2AzSTXuIIGtF5q5KWyEi9Nj93BCWa1Llcddkn3ZEZMvDwR4MacwUj8G8hwoH73VvT3jAiakjSpNEIqYCzofeejdfN/gEuuAUfe8uNbTu+gBS+iP3QJe3Pc0Fs/lKJzd3frPNj7xb83wpOf865EQQoOozhnRIKKcMReSjakr/Px5NNooeiJcWEreDagQO2TbwTnHg1kCNG3BAXV/2lV3XBU4afZBoUfxAzYWFOl6xFCAPzhQCPL1SFJp1VRADY/1MU2Kaje5AZoJ4jjph8+yspxBvjic1vC1uYRGW8LWRind9w4eVhCm0LfPiFRCpP+jKPQOJzcNH580/nIMFXPHHnLKv/It7Qex1unDv/QjkuCFFHR6SWJm4WBrwDek+MyOIvgT6o878Cu0Ps472QpoYBQ+7l2WoylWdG1lHZV1UiHPj7PLHPNAL4rbbN3U88fS6N9OJHegQTfcX0i/1KPk4IN/5Z+/15dHI658BINjRvI/6O1QqaTVZkqM8ORcoGpn6BjAiz5rRhjWpOCwlmT+VzOAp3IqACURS1X+txjWE2mfVjlHLJsvyGRDLv1dUR3IeStDAEfsjR/ruRgn5XTFpYaccB/u//DJonJr5A+KFiLbYl+sbbSVAoQCAiAdxKdUpKPx7C473UJ2nYQGby5H5xwboa0Uj0SnJLYWdQ0jvVvzWpWFVWATc4UqnaxdoUDAmewrM6cSSIAmQBB34orCunFbriK9Z4efZ7gB9erQ1fpi3z/IjQBoTEpOUUIPW/qMAApIDPVM6UV9PumW7RL9zKEP5PuWJoGGnKbWGP/b9G4vMFiWMaSNHBYYMI6OLH4WJ3E+4QBGh2vjjfQ0gobhaLgIerIwCQFYEdl9KddAjaflUEFXal9fIQ8Bz9L3rDhQE5AGBZL6ULZmJe3GnkN6Cc+UWAGyD5zv2rsCG2lvR5ox4UE2mFi6nBJbC5Vj5m9Sz1l0QpRwUkH2kD2QQ5iV6nNmQOcU/mz7ulxluf8+FBJJimYVqK8UkJ6+W6j8Eft9Q8fTpEuEVLxqTWGgOAEUBf87RWDU+iF3A+AxFGsJLc5RC+5BKNTEDlV2qDCjHT7b5wqBKJ3FHulOih9EenlZiI51m6kg5yyxnMdbhasvSh6Az8Mp/4lFo/wSA/mXxNhBrEEmRhFiIE5yYUEYIj5F8fH+93tIuWQqyhXIwCntEOdSSmoei9EYFzj8deXcEzVf8y/N6HQErZcJjyg34caOsfRcJYoxEiCm4icA/btWhdjUNT02B20qnxGFndO4CRUQlyDqTbyVD8LRLK9/95L9+5v9zojLle8xQe30dsxKn7r9TTJH8QQai5iam9lU1ik50lwTKpZb18k4rNdO5cnnYoHzCXeCg38YZxyFt9G7um/MxlID5Qd5Ywq6thDzL7WxvanKeRhCuJ2MTVV0EoJxZKIj9Yv0Ars9mZHkoHoP0ikcW8d5ciDj1Onnbj+XDcYI3FZj0Y2vToZvYi/7eLWi8EnSjaIQrr/AHnrmZK1w3Uicd691U6r3Y0UdnzQEl4Ub/l1uhSaGAg2oEdDxkOdZ3Frvf/C4nTEBmunPlNvnJjVFssdeVVXKLBOZ5eRiJjasHUKnTeJVwolvd/dBI+ypfw1+5ae/0upxd9/gV1lbwX9N2yOwqbxz24cKXZWvOFBAGc3+gQFu8RrF6NAeQ96PlkuRsiNOKPPtJT3JNrLGvVKY8g==
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</saml:EncryptedAssertion>
</samlp:Response>

View file

@ -0,0 +1,29 @@
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8080/sales-post-enc/saml" ID="ID_0b43d444-d1a8-44a5-8caf-38e176489e1f" InResponseTo="ID_223d3591-22fb-4b3c-9e38-4719293b2d94" IssueInstant="2016-11-01T13:52:43.054Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8081/auth/realms/saml-demo</saml:Issuer>
<samlp:Extensions>
<kckey:KeyInfo xmlns:kckey="urn:keycloak:ext:key:1.0" MessageSigningKeyId="FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"/>
</samlp:Extensions>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<xenc:CipherData>
<xenc:CipherValue>
OkvZTx/ifYLef74rY0F9I8lbJaatgSEguo+zwh5JrYWcO09Ib2gtz5+z+67Is2+wk/OzKp154r8qAI5vY9AYvuXCslKL/wbcZ1UILL78F0T/iiUW3VpWy8Wvz5nezBFPRqot8WiFQykByjlBg1Z8XOts+uIdyqBBi/WjYeJGMaQ=
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>
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
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</saml:EncryptedAssertion>
</samlp:Response>

View file

@ -0,0 +1,32 @@
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8081/auth/realms/saml-demo/protocol/saml" ID="ID_4790c6a3-4b9f-4c0a-a368-5c0e498544e4" IssueInstant="2016-11-01T14:36:43.194Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8080/sales-post-enc/</saml:Issuer>
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<dsig:Reference URI="#ID_4790c6a3-4b9f-4c0a-a368-5c0e498544e4">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<dsig:DigestValue>zeWNo5eav5tFOOCEJ1YU9eINkPnBSfixzAr8AOC4R4c=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>
pyOiS1LsV/XR08zhcN6IqSYuKTDln4otmCvZxCc07ORP1C9jragu8V8rEE09qt/zBcdw7Arb8eLNNC6oCnrnMxuvzRInVTwt7T5K3t0UlzRWOb3HMElhcWFEgDzh6uKw5Cr45A01XNpojtJWCML/qU2Enyyy80FBlCJNcbzyLxE=
</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:KeyValue>
<dsig:RSAKeyValue>
<dsig:Modulus>
2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEik=
</dsig:Modulus>
<dsig:Exponent>AQAB</dsig:Exponent>
</dsig:RSAKeyValue>
</dsig:KeyValue>
</dsig:KeyInfo>
</dsig:Signature>
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">bburke</saml:NameID>
<samlp:SessionIndex>a3b2df1c-1095-487b-8b56-f62818c449e3</samlp:SessionIndex>
</samlp:LogoutRequest>