[KEYCLOAK-2894] - Fixing saml signature validation
This commit is contained in:
parent
3e4f5f40dc
commit
60f954a497
30 changed files with 384 additions and 6 deletions
|
@ -45,6 +45,7 @@ public class Constants {
|
|||
static final String KEY_STORE = "KeyStore";
|
||||
static final String SIGN_REQUEST = "signRequest";
|
||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||
static final String REQUEST_BINDING = "requestBinding";
|
||||
static final String BINDING_URL = "bindingUrl";
|
||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||
|
@ -97,6 +98,7 @@ public class Constants {
|
|||
static final String CERTIFICATE_ALIAS = "alias";
|
||||
static final String SIGN_REQUEST = "signRequest";
|
||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||
static final String REQUEST_BINDING = "requestBinding";
|
||||
static final String BINDING_URL = "bindingUrl";
|
||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||
|
|
|
@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
|
|||
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition VALIDATE_ASSERTION_SIGNATURE =
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_ASSERTION_SIGNATURE, ModelType.BOOLEAN, true)
|
||||
.setXmlName(Constants.XML.VALIDATE_ASSERTION_SIGNATURE)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition REQUEST_BINDING =
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
||||
.setXmlName(Constants.XML.REQUEST_BINDING)
|
||||
|
@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
|
|||
.setXmlName(Constants.XML.BINDING_URL)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
|
||||
|
||||
static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ keycloak-saml.IDP.signatureCanonicalizationMethod=Signature canonicalization met
|
|||
keycloak-saml.IDP.SingleSignOnService=Single sign-on configuration
|
||||
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
||||
keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
|
||||
keycloak-saml.IDP.SingleSignOnService.validateAssertionSignature=Validate an SSO assertion signature
|
||||
keycloak-saml.IDP.SingleSignOnService.requestBinding=HTTP method to use for requests
|
||||
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
||||
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
||||
|
|
|
@ -132,6 +132,11 @@
|
|||
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Validate the SSO assertion signature</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="requestBinding" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>HTTP method to use for requests</xs:documentation>
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<IDP entityID="idp">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateResponseSignature="true"
|
||||
validateAssertionSignature="true"
|
||||
requestBinding="POST"
|
||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||
<SingleLogoutService
|
||||
|
|
|
@ -34,6 +34,7 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
|
||||
private boolean signRequest;
|
||||
private boolean validateResponseSignature;
|
||||
private boolean validateAssertionSignature;
|
||||
private Binding requestBinding;
|
||||
private Binding responseBinding;
|
||||
private String requestBindingUrl;
|
||||
|
@ -48,6 +49,11 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateAssertionSignature() {
|
||||
return validateAssertionSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Binding getRequestBinding() {
|
||||
return requestBinding;
|
||||
|
@ -71,6 +77,10 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
||||
this.validateAssertionSignature = validateAssertionSignature;
|
||||
}
|
||||
|
||||
public void setRequestBinding(Binding requestBinding) {
|
||||
this.requestBinding = requestBinding;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ public interface SamlDeployment {
|
|||
public interface SingleSignOnService {
|
||||
boolean signRequest();
|
||||
boolean validateResponseSignature();
|
||||
boolean validateAssertionSignature();
|
||||
Binding getRequestBinding();
|
||||
Binding getResponseBinding();
|
||||
String getRequestBindingUrl();
|
||||
|
|
|
@ -33,6 +33,7 @@ public class IDP implements Serializable {
|
|||
private String requestBinding;
|
||||
private String responseBinding;
|
||||
private String bindingUrl;
|
||||
private boolean validateAssertionSignature;
|
||||
|
||||
public boolean isSignRequest() {
|
||||
return signRequest;
|
||||
|
@ -50,6 +51,14 @@ public class IDP implements Serializable {
|
|||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public boolean isValidateAssertionSignature() {
|
||||
return validateAssertionSignature;
|
||||
}
|
||||
|
||||
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
||||
this.validateAssertionSignature = validateAssertionSignature;
|
||||
}
|
||||
|
||||
public String getRequestBinding() {
|
||||
return requestBinding;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ public class ConfigXmlConstants {
|
|||
public static final String RESPONSE_BINDING_ATTR = "responseBinding";
|
||||
public static final String BINDING_URL_ATTR = "bindingUrl";
|
||||
public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
|
||||
public static final String VALIDATE_ASSERTION_SIGNATURE_ATTR = "validateAssertionSignature";
|
||||
public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
|
||||
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
||||
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
|
||||
|
|
|
@ -149,6 +149,7 @@ public class DeploymentBuilder {
|
|||
}
|
||||
sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
|
||||
sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
|
||||
sso.setValidateAssertionSignature(sp.getIdp().getSingleSignOnService().isValidateAssertionSignature());
|
||||
|
||||
slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
|
||||
slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
|
||||
|
|
|
@ -106,6 +106,7 @@ public class IDPXmlParser extends AbstractParser {
|
|||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
sso.setValidateAssertionSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
|
||||
sso.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||
|
|
|
@ -201,7 +201,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
|||
return AuthOutcome.FAILED;
|
||||
}
|
||||
}
|
||||
return handleLoginResponse((ResponseType) statusResponse, onCreateSession);
|
||||
return handleLoginResponse((ResponseType) statusResponse, postBinding, onCreateSession);
|
||||
} finally {
|
||||
sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
|
||||
}
|
||||
|
@ -272,8 +272,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
|||
return false;
|
||||
}
|
||||
|
||||
protected AuthOutcome handleLoginResponse(ResponseType responseType, OnSessionCreated onCreateSession) {
|
||||
|
||||
protected AuthOutcome handleLoginResponse(ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
|
||||
AssertionType assertion = null;
|
||||
try {
|
||||
assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
|
||||
|
@ -298,6 +297,32 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
|||
};
|
||||
}
|
||||
|
||||
if (deployment.getIDP().getSingleSignOnService().validateAssertionSignature()) {
|
||||
try {
|
||||
validateSamlSignature(new SAMLDocumentHolder(AssertionUtil.asDocument(assertion)), postBinding, GeneralConstants.SAML_RESPONSE_KEY);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Failed to verify saml assertion signature", e);
|
||||
|
||||
challenge = new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE);
|
||||
exchange.getRequest().setError(error);
|
||||
exchange.getResponse().sendError(403);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() {
|
||||
return 403;
|
||||
}
|
||||
};
|
||||
return AuthOutcome.FAILED;
|
||||
} catch (ProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
SubjectType subject = assertion.getSubject();
|
||||
SubjectType.STSubType subType = subject.getSubType();
|
||||
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
<xs:complexType name="sign-on-type">
|
||||
<xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="requestBinding" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="responseBinding" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="bindingUrl" type="xs:string" use="optional"/>
|
||||
|
|
|
@ -45,6 +45,7 @@ public class Constants {
|
|||
static final String KEY_STORE = "KeyStore";
|
||||
static final String SIGN_REQUEST = "signRequest";
|
||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||
static final String REQUEST_BINDING = "requestBinding";
|
||||
static final String BINDING_URL = "bindingUrl";
|
||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||
|
@ -97,6 +98,7 @@ public class Constants {
|
|||
static final String CERTIFICATE_ALIAS = "alias";
|
||||
static final String SIGN_REQUEST = "signRequest";
|
||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||
static final String REQUEST_BINDING = "requestBinding";
|
||||
static final String BINDING_URL = "bindingUrl";
|
||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||
|
|
|
@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
|
|||
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition VALIDATE_ASSERTION_SIGNATURE =
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_ASSERTION_SIGNATURE, ModelType.BOOLEAN, true)
|
||||
.setXmlName(Constants.XML.VALIDATE_ASSERTION_SIGNATURE)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition REQUEST_BINDING =
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
||||
.setXmlName(Constants.XML.REQUEST_BINDING)
|
||||
|
@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
|
|||
.setXmlName(Constants.XML.BINDING_URL)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
|
||||
|
||||
static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ keycloak-saml.IDP.signatureCanonicalizationMethod=Signature canonicalization met
|
|||
keycloak-saml.IDP.SingleSignOnService=Single sign-on configuration
|
||||
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
||||
keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
|
||||
keycloak-saml.IDP.SingleSignOnService.validateAssertionSignature=Validate an SSO assertion signature
|
||||
keycloak-saml.IDP.SingleSignOnService.requestBinding=HTTP method to use for requests
|
||||
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
||||
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
||||
|
|
|
@ -132,6 +132,11 @@
|
|||
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Validate the SSO assertion signature</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="requestBinding" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>HTTP method to use for requests</xs:documentation>
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test" encryption="test">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateResponseSignature="true"
|
||||
validateAssertionSignature="true"
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateResponseSignature="true"
|
||||
validateAssertionSignature="true"
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||
|
|
|
@ -370,7 +370,8 @@ public class XMLSignatureUtil {
|
|||
NodeList nl = signedDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
||||
|
||||
if (nl == null || nl.getLength() == 0) {
|
||||
throw logger.nullValueError("Cannot find Signature element");
|
||||
logger.debug("Cannot find Signature element");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (publicKey == null)
|
||||
|
|
|
@ -96,6 +96,7 @@ public class KeycloakSamlClientInstallation implements ClientInstallationProvide
|
|||
buffer.append(">\n");
|
||||
buffer.append(" <SingleSignOnService signRequest=\"").append(Boolean.toString(samlClient.requiresClientSignature())).append("\"\n");
|
||||
buffer.append(" validateResponseSignature=\"").append(Boolean.toString(samlClient.requiresRealmSignature())).append("\"\n");
|
||||
buffer.append(" validateAssertionSignature=\"").append(Boolean.toString(samlClient.requiresAssertionSignature())).append("\"\n");
|
||||
buffer.append(" requestBinding=\"POST\"\n");
|
||||
UriBuilder bindingUrlBuilder = UriBuilder.fromUri(baseUri);
|
||||
String bindingUrl = RealmsResource.protocolUrl(bindingUrlBuilder)
|
||||
|
|
|
@ -51,6 +51,7 @@ public class SamlAdapterTest {
|
|||
initializeSamlSecuredWar("/keycloak-saml/simple-post2", "/sales-post2", "post.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/simple-post-passive", "/sales-post-passive", "post-passive.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/sales-post-assertion-and-response-sig", "/sales-post-assertion-and-response-sig", "sales-post-assertion-and-response-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader);
|
||||
|
@ -60,6 +61,8 @@ public class SamlAdapterTest {
|
|||
initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/bad-assertion-signed-post", "/bad-assertion-sales-post-sig", "bad-assertion-post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/missing-assertion-sig", "/missing-assertion-sig", "missing-assertion-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
||||
System.setProperty("app.server.base.url", "http://localhost:8081");
|
||||
initializeSamlSecuredWar("/keycloak-saml/simple-input", "/input-portal", "input.war", classLoader, InputServlet.class, "/secured/*");
|
||||
|
@ -89,6 +92,16 @@ public class SamlAdapterTest {
|
|||
testStrategy.testPostBadRealmSignature();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostBadAssertionSignature() {
|
||||
testStrategy.testPostBadAssertionSignature();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingAssertionSignature() {
|
||||
testStrategy.testMissingAssertionSignature();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSimpleUnauthorized() {
|
||||
testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() {
|
||||
|
@ -189,6 +202,11 @@ public class SamlAdapterTest {
|
|||
testStrategy.testPostSignedLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedResponseAndAssertionLoginLogout() {
|
||||
testStrategy.testPostSignedResponseAndAssertionLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIDPDescriptor() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
|
|
|
@ -280,6 +280,16 @@ public class SamlAdapterTestStrategy extends ExternalResource {
|
|||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig?GLO=true");
|
||||
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig/", true);
|
||||
|
||||
}
|
||||
public void testPostSignedResponseAndAssertionLoginLogout() {
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
|
||||
assertAtLoginPagePostBinding();
|
||||
loginPage.login("bburke", "password");
|
||||
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig?GLO=true");
|
||||
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/", true);
|
||||
|
||||
}
|
||||
public void testPostSignedLoginLogoutTransientNameID() {
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
|
||||
|
@ -523,6 +533,32 @@ public class SamlAdapterTestStrategy extends ExternalResource {
|
|||
ErrorServlet.authError = null;
|
||||
}
|
||||
|
||||
public void testPostBadAssertionSignature() {
|
||||
ErrorServlet.authError = null;
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/");
|
||||
assertAtLoginPagePostBinding();
|
||||
loginPage.login("bburke", "password");
|
||||
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/saml");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertNotNull(ErrorServlet.authError);
|
||||
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
|
||||
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
|
||||
ErrorServlet.authError = null;
|
||||
}
|
||||
|
||||
public void testMissingAssertionSignature() {
|
||||
ErrorServlet.authError = null;
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/missing-assertion-sig/");
|
||||
assertAtLoginPagePostBinding();
|
||||
loginPage.login("bburke", "password");
|
||||
assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/missing-assertion-sig/saml");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertNotNull(ErrorServlet.authError);
|
||||
SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
|
||||
Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
|
||||
ErrorServlet.authError = null;
|
||||
}
|
||||
|
||||
public void testMetadataPostSignedLoginLogout() throws Exception {
|
||||
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata/");
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<keycloak-saml-adapter>
|
||||
<SP entityID="http://localhost:8081/bad-assertion-sales-post-sig/"
|
||||
sslPolicy="EXTERNAL"
|
||||
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||
logoutPage="/logout.jsp"
|
||||
forceAuthentication="false">
|
||||
<Keys>
|
||||
<Key signing="true" >
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<PrivateKey alias="http://localhost:8081/bad-realm-sales-post-sig/" password="test123"/>
|
||||
<Certificate alias="http://localhost:8081/bad-realm-sales-post-sig/"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
<PrincipalNameMapping policy="FROM_NAME_ID"/>
|
||||
<RoleIdentifiers>
|
||||
<Attribute name="Role"/>
|
||||
</RoleIdentifiers>
|
||||
<IDP entityID="idp">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateAssertionSignature="true"
|
||||
requestBinding="POST"
|
||||
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
|
||||
<SingleLogoutService
|
||||
validateRequestSignature="true"
|
||||
validateResponseSignature="true"
|
||||
signRequest="true"
|
||||
signResponse="true"
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
<Keys>
|
||||
<Key signing="true">
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<Certificate alias="demo"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
</IDP>
|
||||
</SP>
|
||||
</keycloak-saml-adapter>
|
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
<!--
|
||||
~ JBoss, Home of Professional Open Source.
|
||||
~ Copyright 2016 Red Hat, Inc., and individual 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.
|
||||
-->
|
||||
|
||||
<keycloak-saml-adapter>
|
||||
<SP entityID="http://localhost:8081/missing-assertion-sig/"
|
||||
sslPolicy="EXTERNAL"
|
||||
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||
logoutPage="/logout.jsp"
|
||||
forceAuthentication="false">
|
||||
<Keys>
|
||||
<Key signing="true" >
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
|
||||
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
<PrincipalNameMapping policy="FROM_NAME_ID"/>
|
||||
<RoleIdentifiers>
|
||||
<Attribute name="Role"/>
|
||||
</RoleIdentifiers>
|
||||
<IDP entityID="idp"
|
||||
signaturesRequired="true">
|
||||
<SingleSignOnService requestBinding="POST"
|
||||
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
validateAssertionSignature="true"
|
||||
validateResponseSignature="false"
|
||||
/>
|
||||
|
||||
<SingleLogoutService
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
<Keys>
|
||||
<Key signing="true">
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<Certificate alias="demo"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
</IDP>
|
||||
</SP>
|
||||
</keycloak-saml-adapter>
|
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
<!--
|
||||
~ JBoss, Home of Professional Open Source.
|
||||
~ Copyright 2016 Red Hat, Inc., and individual 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.
|
||||
-->
|
||||
|
||||
<keycloak-saml-adapter>
|
||||
<SP entityID="http://localhost:8081/sales-post-assertion-and-response-sig/"
|
||||
sslPolicy="EXTERNAL"
|
||||
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||
logoutPage="/logout.jsp"
|
||||
forceAuthentication="false">
|
||||
<Keys>
|
||||
<Key signing="true" >
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
|
||||
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
<PrincipalNameMapping policy="FROM_NAME_ID"/>
|
||||
<RoleIdentifiers>
|
||||
<Attribute name="Role"/>
|
||||
</RoleIdentifiers>
|
||||
<IDP entityID="idp"
|
||||
signaturesRequired="true">
|
||||
<SingleSignOnService requestBinding="POST"
|
||||
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
validateAssertionSignature="true"
|
||||
validateResponseSignature="true"
|
||||
/>
|
||||
|
||||
<SingleLogoutService
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
<Keys>
|
||||
<Key signing="true">
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<Certificate alias="demo"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
</IDP>
|
||||
</SP>
|
||||
</keycloak-saml-adapter>
|
Binary file not shown.
|
@ -158,6 +158,50 @@
|
|||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-assertion-and-response-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-assertion-and-response-sig",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-assertion-and-response-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
|
||||
"saml.server.signature": "true",
|
||||
"saml.assertion.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/missing-assertion-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/missing-assertion-sig",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/missing-assertion-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/missing-assertion-sig/saml",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/missing-assertion-sig/saml",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/missing-assertion-sig/saml",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/missing-assertion-sig/saml",
|
||||
"saml.server.signature": "true",
|
||||
"saml.assertion.signature": "false",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"enabled": true,
|
||||
|
@ -242,6 +286,23 @@
|
|||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/bad-assertion-sales-post-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/bad-assertion-sales-post-sig/",
|
||||
"adminUrl": "http://localhost:8081/bad-assertion-sales-post-sig/saml",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/bad-assertion-sales-post-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.assertion.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/bad-client-sales-post-sig/",
|
||||
"enabled": true,
|
||||
|
@ -274,6 +335,7 @@
|
|||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/saml",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/saml",
|
||||
"saml.server.signature": "true",
|
||||
"saml.assertion.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA512",
|
||||
"saml.client.signature": "true",
|
||||
"saml.encrypt": "true",
|
||||
|
|
Loading…
Reference in a new issue