Merge pull request #3824 from mhajas/KEYCLOAK-4020
KEYCLOAK-4020 add test for boolean attribute
This commit is contained in:
commit
6602123b55
7 changed files with 239 additions and 43 deletions
|
@ -85,6 +85,7 @@ public class SendUsernameServlet {
|
||||||
@Path("getAttributes")
|
@Path("getAttributes")
|
||||||
public Response getSentPrincipal() throws IOException {
|
public Response getSentPrincipal() throws IOException {
|
||||||
System.out.println("In SendUsername Servlet getSentPrincipal()");
|
System.out.println("In SendUsername Servlet getSentPrincipal()");
|
||||||
|
sentPrincipal = httpServletRequest.getUserPrincipal();
|
||||||
|
|
||||||
return Response.ok(getAttributes()).header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_TYPE + ";charset=UTF-8").build();
|
return Response.ok(getAttributes()).header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_TYPE + ";charset=UTF-8").build();
|
||||||
|
|
||||||
|
@ -190,6 +191,7 @@ public class SendUsernameServlet {
|
||||||
SamlPrincipal principal = (SamlPrincipal) sentPrincipal;
|
SamlPrincipal principal = (SamlPrincipal) sentPrincipal;
|
||||||
String output = "attribute email: " + principal.getAttribute(X500SAMLProfileConstants.EMAIL.get());
|
String output = "attribute email: " + principal.getAttribute(X500SAMLProfileConstants.EMAIL.get());
|
||||||
output += "<br /> topAttribute: " + principal.getAttribute("topAttribute");
|
output += "<br /> topAttribute: " + principal.getAttribute("topAttribute");
|
||||||
|
output += "<br /> boolean-attribute: " + principal.getAttribute("boolean-attribute");
|
||||||
output += "<br /> level2Attribute: " + principal.getAttribute("level2Attribute");
|
output += "<br /> level2Attribute: " + principal.getAttribute("level2Attribute");
|
||||||
output += "<br /> group: " + principal.getAttributes("group").toString();
|
output += "<br /> group: " + principal.getAttributes("group").toString();
|
||||||
output += "<br /> friendlyAttribute email: " + principal.getFriendlyAttribute("email");
|
output += "<br /> friendlyAttribute email: " + principal.getFriendlyAttribute("email");
|
||||||
|
|
|
@ -206,20 +206,25 @@ public class IOUtil {
|
||||||
return currentElement.getTextContent();
|
return currentElement.getTextContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void appendChildInDocument(Document doc, String parentTag, Element node) {
|
public static void appendChildInDocument(Document doc, String parentPath, Element node) {
|
||||||
NodeList nodes = doc.getElementsByTagName(parentTag);
|
String[] pathSegments = parentPath.split("/");
|
||||||
if (nodes.getLength() != 1) {
|
|
||||||
log.warn("Not able or ambiguous to find element: " + parentTag);
|
Element currentElement = (Element) doc.getElementsByTagName(pathSegments[0]).item(0);
|
||||||
|
if (currentElement == null) {
|
||||||
|
log.warn("Not able to find element: " + pathSegments[0] + " in document");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element parentElement = (Element) nodes.item(0);
|
for (int i = 1; i < pathSegments.length; i++) {
|
||||||
if (parentElement == null) {
|
currentElement = (Element) currentElement.getElementsByTagName(pathSegments[i]).item(0);
|
||||||
log.warn("Not able to find element: " + parentTag);
|
|
||||||
return;
|
if (currentElement == null) {
|
||||||
|
log.warn("Not able to find element: " + pathSegments[i] + " in " + pathSegments[i - 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parentElement.appendChild(node);
|
currentElement.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void execCommand(String command, File dir) throws IOException, InterruptedException {
|
public static void execCommand(String command, File dir) throws IOException, InterruptedException {
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.adapter.servlet;
|
package org.keycloak.testsuite.adapter.servlet;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.client.protocol.HttpClientContext;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
import org.jboss.arquillian.container.test.api.Deployment;
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
@ -28,10 +35,12 @@ import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||||
import org.keycloak.admin.client.resource.RoleScopeResource;
|
import org.keycloak.admin.client.resource.RoleScopeResource;
|
||||||
import org.keycloak.common.util.KeyUtils;
|
import org.keycloak.common.util.KeyUtils;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
|
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||||
import org.keycloak.keys.Attributes;
|
import org.keycloak.keys.Attributes;
|
||||||
import org.keycloak.keys.KeyProvider;
|
import org.keycloak.keys.KeyProvider;
|
||||||
import org.keycloak.keys.ImportedRsaKeyProviderFactory;
|
import org.keycloak.keys.ImportedRsaKeyProviderFactory;
|
||||||
import org.keycloak.protocol.saml.SamlConfigAttributes;
|
import org.keycloak.protocol.saml.SamlConfigAttributes;
|
||||||
|
import org.keycloak.protocol.saml.SamlProtocol;
|
||||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||||
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
||||||
|
@ -44,6 +53,9 @@ import org.keycloak.saml.BaseSAML2BindingBuilder;
|
||||||
import org.keycloak.saml.SAML2ErrorResponseBuilder;
|
import org.keycloak.saml.SAML2ErrorResponseBuilder;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer;
|
import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer;
|
||||||
|
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
|
||||||
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||||
import org.keycloak.testsuite.adapter.page.BadAssertionSalesPostSig;
|
import org.keycloak.testsuite.adapter.page.BadAssertionSalesPostSig;
|
||||||
import org.keycloak.testsuite.adapter.page.BadClientSalesPostSigServlet;
|
import org.keycloak.testsuite.adapter.page.BadClientSalesPostSigServlet;
|
||||||
|
@ -73,11 +85,12 @@ import org.keycloak.testsuite.auth.page.login.Login;
|
||||||
import org.keycloak.testsuite.auth.page.login.SAMLIDPInitiatedLogin;
|
import org.keycloak.testsuite.auth.page.login.SAMLIDPInitiatedLogin;
|
||||||
import org.keycloak.testsuite.page.AbstractPage;
|
import org.keycloak.testsuite.page.AbstractPage;
|
||||||
import org.keycloak.testsuite.util.IOUtil;
|
import org.keycloak.testsuite.util.IOUtil;
|
||||||
import org.keycloak.testsuite.util.RealmBuilder;
|
import org.keycloak.testsuite.util.SamlClient;
|
||||||
import org.keycloak.testsuite.util.UserBuilder;
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
|
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.ws.rs.client.Client;
|
import javax.ws.rs.client.Client;
|
||||||
|
@ -87,6 +100,8 @@ import javax.ws.rs.client.WebTarget;
|
||||||
import javax.ws.rs.core.Form;
|
import javax.ws.rs.core.Form;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
import javax.ws.rs.core.UriBuilderException;
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
@ -107,13 +122,15 @@ import java.util.stream.Collectors;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
||||||
import static org.keycloak.testsuite.AbstractAuthTest.createUserRepresentation;
|
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
|
import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
|
||||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
|
||||||
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
||||||
import static org.keycloak.testsuite.util.IOUtil.loadXML;
|
import static org.keycloak.testsuite.util.IOUtil.loadXML;
|
||||||
import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
|
import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
|
||||||
|
import static org.keycloak.testsuite.util.Matchers.bodyHC;
|
||||||
|
import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
|
||||||
|
import static org.keycloak.testsuite.util.SamlClient.login;
|
||||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
|
||||||
|
@ -965,6 +982,61 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
|
||||||
response.close();
|
response.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
//KEYCLOAK-4020
|
||||||
|
public void testBooleanAttribute() throws Exception {
|
||||||
|
AuthnRequestType req = SamlClient.createLoginRequestDocument("http://localhost:8081/employee2/", getAppServerSamlEndpoint(employee2ServletPage).toString(), getAuthServerSamlEndpoint(SAMLSERVLETDEMO));
|
||||||
|
Document doc = SAML2Request.convert(req);
|
||||||
|
|
||||||
|
SAMLDocumentHolder res = login(bburkeUser, getAuthServerSamlEndpoint(SAMLSERVLETDEMO), doc, null, SamlClient.Binding.POST, SamlClient.Binding.POST);
|
||||||
|
Document responseDoc = res.getSamlDocument();
|
||||||
|
|
||||||
|
Element attribute = responseDoc.createElement("saml:Attribute");
|
||||||
|
attribute.setAttribute("Name", "boolean-attribute");
|
||||||
|
attribute.setAttribute("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic");
|
||||||
|
|
||||||
|
Element attributeValue = responseDoc.createElement("saml:AttributeValue");
|
||||||
|
attributeValue.setAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema");
|
||||||
|
attributeValue.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
||||||
|
attributeValue.setAttribute("xsi:type", "xs:boolean");
|
||||||
|
attributeValue.setTextContent("true");
|
||||||
|
|
||||||
|
attribute.appendChild(attributeValue);
|
||||||
|
IOUtil.appendChildInDocument(responseDoc, "samlp:Response/saml:Assertion/saml:AttributeStatement", attribute);
|
||||||
|
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
|
||||||
|
HttpClientContext context = HttpClientContext.create();
|
||||||
|
|
||||||
|
HttpUriRequest post = SamlClient.Binding.POST.createSamlPostUnsignedRequest(getAppServerSamlEndpoint(employee2ServletPage), null, responseDoc);
|
||||||
|
response = client.execute(post, context);
|
||||||
|
assertThat(response, statusCodeIsHC(Response.Status.FOUND));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
HttpGet get = new HttpGet(employee2ServletPage.toString() + "/getAttributes");
|
||||||
|
response = client.execute(get);
|
||||||
|
assertThat(response, statusCodeIsHC(Response.Status.OK));
|
||||||
|
assertThat(response, bodyHC(containsString("boolean-attribute: true")));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
} finally {
|
||||||
|
if (response != null) {
|
||||||
|
EntityUtils.consumeQuietly(response.getEntity());
|
||||||
|
try { response.close(); } catch (IOException ex) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI getAuthServerSamlEndpoint(String realm) throws IllegalArgumentException, UriBuilderException {
|
||||||
|
return RealmsResource
|
||||||
|
.protocolUrl(UriBuilder.fromUri(getAuthServerRoot()))
|
||||||
|
.build(realm, SamlProtocol.LOGIN_PROTOCOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI getAppServerSamlEndpoint(SAMLServlet page) throws IllegalArgumentException, UriBuilderException {
|
||||||
|
return UriBuilder.fromPath(page.toString()).path("/saml").build();
|
||||||
|
}
|
||||||
|
|
||||||
private void validateXMLWithSchema(String xml, String schemaFileName) throws SAXException, IOException {
|
private void validateXMLWithSchema(String xml, String schemaFileName) throws SAXException, IOException {
|
||||||
URL schemaFile = getClass().getResource(schemaFileName);
|
URL schemaFile = getClass().getResource(schemaFileName);
|
||||||
|
|
||||||
|
|
|
@ -67,38 +67,6 @@ public class AuthnRequestNameIdFormatTest extends AbstractAuthTest {
|
||||||
private static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/";
|
private static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/";
|
||||||
private static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8081/sales-post/";
|
private static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8081/sales-post/";
|
||||||
|
|
||||||
public static SAMLDocumentHolder login(UserRepresentation user, URI samlEndpoint,
|
|
||||||
Document samlRequest, String relayState, Binding requestBinding, Binding expectedResponseBinding) {
|
|
||||||
CloseableHttpResponse response = null;
|
|
||||||
SamlClient.RedirectStrategyWithSwitchableFollowRedirect strategy = new SamlClient.RedirectStrategyWithSwitchableFollowRedirect();
|
|
||||||
try (CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(strategy).build()) {
|
|
||||||
HttpClientContext context = HttpClientContext.create();
|
|
||||||
|
|
||||||
HttpUriRequest post = requestBinding.createSamlRequest(samlEndpoint, relayState, samlRequest);
|
|
||||||
response = client.execute(post, context);
|
|
||||||
|
|
||||||
assertThat(response, statusCodeIsHC(Response.Status.OK));
|
|
||||||
String loginPageText = EntityUtils.toString(response.getEntity(), "UTF-8");
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
assertThat(loginPageText, containsString("login"));
|
|
||||||
|
|
||||||
HttpUriRequest loginRequest = handleLoginPage(user, loginPageText);
|
|
||||||
|
|
||||||
strategy.setRedirectable(false);
|
|
||||||
response = client.execute(loginRequest, context);
|
|
||||||
|
|
||||||
return expectedResponseBinding.extractResponse(response);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
try { response.close(); } catch (IOException ex) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml.json"));
|
testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml.json"));
|
||||||
|
|
|
@ -38,6 +38,15 @@ public class Matchers {
|
||||||
return new ResponseBodyMatcher(matcher);
|
return new ResponseBodyMatcher(matcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher on HTTP body of a {@link Response} instance.
|
||||||
|
* @param matcher
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Matcher<HttpResponse> bodyHC(Matcher<String> matcher) {
|
||||||
|
return new HttpResponseBodyMatcher(matcher);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matcher on HTTP status code of a {@link Response} instance.
|
* Matcher on HTTP status code of a {@link Response} instance.
|
||||||
* @param matcher
|
* @param matcher
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.util;
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
|
import org.apache.http.client.protocol.HttpClientContext;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.saml.BaseSAML2BindingBuilder;
|
import org.keycloak.saml.BaseSAML2BindingBuilder;
|
||||||
|
@ -106,6 +109,40 @@ public class SamlClient {
|
||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpPost createSamlPostUnsignedRequest(URI samlEndpoint, String relayState, Document samlRequest) {
|
||||||
|
HttpPost post = new HttpPost(samlEndpoint);
|
||||||
|
|
||||||
|
List<NameValuePair> parameters = new LinkedList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
parameters.add(
|
||||||
|
new BasicNameValuePair(GeneralConstants.SAML_RESPONSE_KEY,
|
||||||
|
new BaseSAML2BindingBuilder()
|
||||||
|
.postBinding(samlRequest)
|
||||||
|
.encoded())
|
||||||
|
);
|
||||||
|
} catch (IOException | ConfigurationException | ProcessingException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relayState != null) {
|
||||||
|
parameters.add(new BasicNameValuePair(GeneralConstants.RELAY_STATE, relayState));
|
||||||
|
}
|
||||||
|
|
||||||
|
UrlEncodedFormEntity formEntity;
|
||||||
|
|
||||||
|
try {
|
||||||
|
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
post.setEntity(formEntity);
|
||||||
|
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getBindingUri() {
|
public URI getBindingUri() {
|
||||||
return URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
|
return URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
|
||||||
|
@ -138,11 +175,17 @@ public class SamlClient {
|
||||||
public URI getBindingUri() {
|
public URI getBindingUri() {
|
||||||
return URI.create(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
|
return URI.create(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpUriRequest createSamlPostUnsignedRequest(URI samlEndpoint, String relayState, Document samlRequest) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public abstract SAMLDocumentHolder extractResponse(CloseableHttpResponse response) throws IOException;
|
public abstract SAMLDocumentHolder extractResponse(CloseableHttpResponse response) throws IOException;
|
||||||
public abstract HttpUriRequest createSamlRequest(URI samlEndpoint, String relayState, Document samlRequest);
|
public abstract HttpUriRequest createSamlRequest(URI samlEndpoint, String relayState, Document samlRequest);
|
||||||
public abstract URI getBindingUri();
|
public abstract URI getBindingUri();
|
||||||
|
public abstract HttpUriRequest createSamlPostUnsignedRequest(URI samlEndpoint, String relayState, Document samlRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RedirectStrategyWithSwitchableFollowRedirect extends LaxRedirectStrategy {
|
public static class RedirectStrategyWithSwitchableFollowRedirect extends LaxRedirectStrategy {
|
||||||
|
@ -263,4 +306,46 @@ public class SamlClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send request for login form and then login using user param
|
||||||
|
* @param user
|
||||||
|
* @param samlEndpoint
|
||||||
|
* @param samlRequest
|
||||||
|
* @param relayState
|
||||||
|
* @param requestBinding
|
||||||
|
* @param expectedResponseBinding
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static SAMLDocumentHolder login(UserRepresentation user, URI samlEndpoint,
|
||||||
|
Document samlRequest, String relayState, Binding requestBinding, Binding expectedResponseBinding) {
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
SamlClient.RedirectStrategyWithSwitchableFollowRedirect strategy = new SamlClient.RedirectStrategyWithSwitchableFollowRedirect();
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(strategy).build()) {
|
||||||
|
HttpClientContext context = HttpClientContext.create();
|
||||||
|
|
||||||
|
HttpUriRequest post = requestBinding.createSamlRequest(samlEndpoint, relayState, samlRequest);
|
||||||
|
response = client.execute(post, context);
|
||||||
|
|
||||||
|
assertThat(response, statusCodeIsHC(Response.Status.OK));
|
||||||
|
String loginPageText = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
assertThat(loginPageText, containsString("login"));
|
||||||
|
|
||||||
|
HttpUriRequest loginRequest = handleLoginPage(user, loginPageText);
|
||||||
|
|
||||||
|
strategy.setRedirectable(false);
|
||||||
|
response = client.execute(loginRequest, context);
|
||||||
|
|
||||||
|
return expectedResponseBinding.extractResponse(response);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
} finally {
|
||||||
|
if (response != null) {
|
||||||
|
EntityUtils.consumeQuietly(response.getEntity());
|
||||||
|
try { response.close(); } catch (IOException ex) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.matchers;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.hamcrest.BaseMatcher;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher for matching status code of {@link Response} instance.
|
||||||
|
* @author hmlnarik
|
||||||
|
*/
|
||||||
|
public class HttpResponseBodyMatcher extends BaseMatcher<HttpResponse> {
|
||||||
|
|
||||||
|
private final Matcher<String> matcher;
|
||||||
|
|
||||||
|
public HttpResponseBodyMatcher(Matcher<String> matcher) {
|
||||||
|
this.matcher = matcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item) {
|
||||||
|
try {
|
||||||
|
return (item instanceof HttpResponse) && this.matcher.matches(EntityUtils.toString(((HttpResponse) item).getEntity()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText("response body matches ").appendDescriptionOf(this.matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue