[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 KEY_STORE = "KeyStore";
|
||||||
static final String SIGN_REQUEST = "signRequest";
|
static final String SIGN_REQUEST = "signRequest";
|
||||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||||
|
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||||
static final String REQUEST_BINDING = "requestBinding";
|
static final String REQUEST_BINDING = "requestBinding";
|
||||||
static final String BINDING_URL = "bindingUrl";
|
static final String BINDING_URL = "bindingUrl";
|
||||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||||
|
@ -97,6 +98,7 @@ public class Constants {
|
||||||
static final String CERTIFICATE_ALIAS = "alias";
|
static final String CERTIFICATE_ALIAS = "alias";
|
||||||
static final String SIGN_REQUEST = "signRequest";
|
static final String SIGN_REQUEST = "signRequest";
|
||||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||||
|
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||||
static final String REQUEST_BINDING = "requestBinding";
|
static final String REQUEST_BINDING = "requestBinding";
|
||||||
static final String BINDING_URL = "bindingUrl";
|
static final String BINDING_URL = "bindingUrl";
|
||||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||||
|
|
|
@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
|
||||||
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
||||||
.build();
|
.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 =
|
static final SimpleAttributeDefinition REQUEST_BINDING =
|
||||||
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
||||||
.setXmlName(Constants.XML.REQUEST_BINDING)
|
.setXmlName(Constants.XML.REQUEST_BINDING)
|
||||||
|
@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
|
||||||
.setXmlName(Constants.XML.BINDING_URL)
|
.setXmlName(Constants.XML.BINDING_URL)
|
||||||
.build();
|
.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<>();
|
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=Single sign-on configuration
|
||||||
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
||||||
keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
|
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.requestBinding=HTTP method to use for requests
|
||||||
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
||||||
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
||||||
|
|
|
@ -132,6 +132,11 @@
|
||||||
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</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:attribute name="requestBinding" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>HTTP method to use for requests</xs:documentation>
|
<xs:documentation>HTTP method to use for requests</xs:documentation>
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
<IDP entityID="idp">
|
<IDP entityID="idp">
|
||||||
<SingleSignOnService signRequest="true"
|
<SingleSignOnService signRequest="true"
|
||||||
validateResponseSignature="true"
|
validateResponseSignature="true"
|
||||||
|
validateAssertionSignature="true"
|
||||||
requestBinding="POST"
|
requestBinding="POST"
|
||||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||||
<SingleLogoutService
|
<SingleLogoutService
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
||||||
public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
|
public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
|
||||||
private boolean signRequest;
|
private boolean signRequest;
|
||||||
private boolean validateResponseSignature;
|
private boolean validateResponseSignature;
|
||||||
|
private boolean validateAssertionSignature;
|
||||||
private Binding requestBinding;
|
private Binding requestBinding;
|
||||||
private Binding responseBinding;
|
private Binding responseBinding;
|
||||||
private String requestBindingUrl;
|
private String requestBindingUrl;
|
||||||
|
@ -48,6 +49,11 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
||||||
return validateResponseSignature;
|
return validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateAssertionSignature() {
|
||||||
|
return validateAssertionSignature;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Binding getRequestBinding() {
|
public Binding getRequestBinding() {
|
||||||
return requestBinding;
|
return requestBinding;
|
||||||
|
@ -71,6 +77,10 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
||||||
this.validateResponseSignature = validateResponseSignature;
|
this.validateResponseSignature = validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
||||||
|
this.validateAssertionSignature = validateAssertionSignature;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRequestBinding(Binding requestBinding) {
|
public void setRequestBinding(Binding requestBinding) {
|
||||||
this.requestBinding = requestBinding;
|
this.requestBinding = requestBinding;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ public interface SamlDeployment {
|
||||||
public interface SingleSignOnService {
|
public interface SingleSignOnService {
|
||||||
boolean signRequest();
|
boolean signRequest();
|
||||||
boolean validateResponseSignature();
|
boolean validateResponseSignature();
|
||||||
|
boolean validateAssertionSignature();
|
||||||
Binding getRequestBinding();
|
Binding getRequestBinding();
|
||||||
Binding getResponseBinding();
|
Binding getResponseBinding();
|
||||||
String getRequestBindingUrl();
|
String getRequestBindingUrl();
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class IDP implements Serializable {
|
||||||
private String requestBinding;
|
private String requestBinding;
|
||||||
private String responseBinding;
|
private String responseBinding;
|
||||||
private String bindingUrl;
|
private String bindingUrl;
|
||||||
|
private boolean validateAssertionSignature;
|
||||||
|
|
||||||
public boolean isSignRequest() {
|
public boolean isSignRequest() {
|
||||||
return signRequest;
|
return signRequest;
|
||||||
|
@ -50,6 +51,14 @@ public class IDP implements Serializable {
|
||||||
this.validateResponseSignature = validateResponseSignature;
|
this.validateResponseSignature = validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValidateAssertionSignature() {
|
||||||
|
return validateAssertionSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
||||||
|
this.validateAssertionSignature = validateAssertionSignature;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRequestBinding() {
|
public String getRequestBinding() {
|
||||||
return requestBinding;
|
return requestBinding;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ public class ConfigXmlConstants {
|
||||||
public static final String RESPONSE_BINDING_ATTR = "responseBinding";
|
public static final String RESPONSE_BINDING_ATTR = "responseBinding";
|
||||||
public static final String BINDING_URL_ATTR = "bindingUrl";
|
public static final String BINDING_URL_ATTR = "bindingUrl";
|
||||||
public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
|
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 VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
|
||||||
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
||||||
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
|
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
|
||||||
|
|
|
@ -149,6 +149,7 @@ public class DeploymentBuilder {
|
||||||
}
|
}
|
||||||
sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
|
sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
|
||||||
sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
|
sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
|
||||||
|
sso.setValidateAssertionSignature(sp.getIdp().getSingleSignOnService().isValidateAssertionSignature());
|
||||||
|
|
||||||
slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
|
slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
|
||||||
slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
|
slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
|
||||||
|
|
|
@ -106,6 +106,7 @@ public class IDPXmlParser extends AbstractParser {
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||||
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||||
sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_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.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||||
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||||
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||||
|
|
|
@ -201,7 +201,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||||
return AuthOutcome.FAILED;
|
return AuthOutcome.FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handleLoginResponse((ResponseType) statusResponse, onCreateSession);
|
return handleLoginResponse((ResponseType) statusResponse, postBinding, onCreateSession);
|
||||||
} finally {
|
} finally {
|
||||||
sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
|
sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AuthOutcome handleLoginResponse(ResponseType responseType, OnSessionCreated onCreateSession) {
|
protected AuthOutcome handleLoginResponse(ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
|
||||||
|
|
||||||
AssertionType assertion = null;
|
AssertionType assertion = null;
|
||||||
try {
|
try {
|
||||||
assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
|
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 subject = assertion.getSubject();
|
||||||
SubjectType.STSubType subType = subject.getSubType();
|
SubjectType.STSubType subType = subject.getSubType();
|
||||||
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
<xs:complexType name="sign-on-type">
|
<xs:complexType name="sign-on-type">
|
||||||
<xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
|
<xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
|
||||||
<xs:attribute name="validateResponseSignature" 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="requestBinding" type="xs:string" use="optional"/>
|
||||||
<xs:attribute name="responseBinding" type="xs:string" use="optional"/>
|
<xs:attribute name="responseBinding" type="xs:string" use="optional"/>
|
||||||
<xs:attribute name="bindingUrl" 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 KEY_STORE = "KeyStore";
|
||||||
static final String SIGN_REQUEST = "signRequest";
|
static final String SIGN_REQUEST = "signRequest";
|
||||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||||
|
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||||
static final String REQUEST_BINDING = "requestBinding";
|
static final String REQUEST_BINDING = "requestBinding";
|
||||||
static final String BINDING_URL = "bindingUrl";
|
static final String BINDING_URL = "bindingUrl";
|
||||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||||
|
@ -97,6 +98,7 @@ public class Constants {
|
||||||
static final String CERTIFICATE_ALIAS = "alias";
|
static final String CERTIFICATE_ALIAS = "alias";
|
||||||
static final String SIGN_REQUEST = "signRequest";
|
static final String SIGN_REQUEST = "signRequest";
|
||||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||||
|
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||||
static final String REQUEST_BINDING = "requestBinding";
|
static final String REQUEST_BINDING = "requestBinding";
|
||||||
static final String BINDING_URL = "bindingUrl";
|
static final String BINDING_URL = "bindingUrl";
|
||||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||||
|
|
|
@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
|
||||||
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
.setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
|
||||||
.build();
|
.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 =
|
static final SimpleAttributeDefinition REQUEST_BINDING =
|
||||||
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
|
||||||
.setXmlName(Constants.XML.REQUEST_BINDING)
|
.setXmlName(Constants.XML.REQUEST_BINDING)
|
||||||
|
@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
|
||||||
.setXmlName(Constants.XML.BINDING_URL)
|
.setXmlName(Constants.XML.BINDING_URL)
|
||||||
.build();
|
.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<>();
|
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=Single sign-on configuration
|
||||||
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
|
||||||
keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
|
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.requestBinding=HTTP method to use for requests
|
||||||
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
||||||
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
||||||
|
|
|
@ -132,6 +132,11 @@
|
||||||
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
<xs:documentation>Validate the SSO response signature</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</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:attribute name="requestBinding" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>HTTP method to use for requests</xs:documentation>
|
<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">
|
<IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test" encryption="test">
|
||||||
<SingleSignOnService signRequest="true"
|
<SingleSignOnService signRequest="true"
|
||||||
validateResponseSignature="true"
|
validateResponseSignature="true"
|
||||||
|
validateAssertionSignature="true"
|
||||||
requestBinding="POST"
|
requestBinding="POST"
|
||||||
responseBinding="POST"
|
responseBinding="POST"
|
||||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test">
|
<IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test">
|
||||||
<SingleSignOnService signRequest="true"
|
<SingleSignOnService signRequest="true"
|
||||||
validateResponseSignature="true"
|
validateResponseSignature="true"
|
||||||
|
validateAssertionSignature="true"
|
||||||
requestBinding="POST"
|
requestBinding="POST"
|
||||||
responseBinding="POST"
|
responseBinding="POST"
|
||||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||||
|
|
|
@ -370,7 +370,8 @@ public class XMLSignatureUtil {
|
||||||
NodeList nl = signedDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
NodeList nl = signedDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
||||||
|
|
||||||
if (nl == null || nl.getLength() == 0) {
|
if (nl == null || nl.getLength() == 0) {
|
||||||
throw logger.nullValueError("Cannot find Signature element");
|
logger.debug("Cannot find Signature element");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publicKey == null)
|
if (publicKey == null)
|
||||||
|
|
|
@ -96,6 +96,7 @@ public class KeycloakSamlClientInstallation implements ClientInstallationProvide
|
||||||
buffer.append(">\n");
|
buffer.append(">\n");
|
||||||
buffer.append(" <SingleSignOnService signRequest=\"").append(Boolean.toString(samlClient.requiresClientSignature())).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(" validateResponseSignature=\"").append(Boolean.toString(samlClient.requiresRealmSignature())).append("\"\n");
|
||||||
|
buffer.append(" validateAssertionSignature=\"").append(Boolean.toString(samlClient.requiresAssertionSignature())).append("\"\n");
|
||||||
buffer.append(" requestBinding=\"POST\"\n");
|
buffer.append(" requestBinding=\"POST\"\n");
|
||||||
UriBuilder bindingUrlBuilder = UriBuilder.fromUri(baseUri);
|
UriBuilder bindingUrlBuilder = UriBuilder.fromUri(baseUri);
|
||||||
String bindingUrl = RealmsResource.protocolUrl(bindingUrlBuilder)
|
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-post2", "/sales-post2", "post.war", classLoader);
|
||||||
initializeSamlSecuredWar("/keycloak-saml/simple-post-passive", "/sales-post-passive", "post-passive.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/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-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-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);
|
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/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-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-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);
|
initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
||||||
System.setProperty("app.server.base.url", "http://localhost:8081");
|
System.setProperty("app.server.base.url", "http://localhost:8081");
|
||||||
initializeSamlSecuredWar("/keycloak-saml/simple-input", "/input-portal", "input.war", classLoader, InputServlet.class, "/secured/*");
|
initializeSamlSecuredWar("/keycloak-saml/simple-input", "/input-portal", "input.war", classLoader, InputServlet.class, "/secured/*");
|
||||||
|
@ -89,6 +92,16 @@ public class SamlAdapterTest {
|
||||||
testStrategy.testPostBadRealmSignature();
|
testStrategy.testPostBadRealmSignature();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostBadAssertionSignature() {
|
||||||
|
testStrategy.testPostBadAssertionSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMissingAssertionSignature() {
|
||||||
|
testStrategy.testMissingAssertionSignature();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostSimpleUnauthorized() {
|
public void testPostSimpleUnauthorized() {
|
||||||
testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() {
|
testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() {
|
||||||
|
@ -189,6 +202,11 @@ public class SamlAdapterTest {
|
||||||
testStrategy.testPostSignedLoginLogout();
|
testStrategy.testPostSignedLoginLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostSignedResponseAndAssertionLoginLogout() {
|
||||||
|
testStrategy.testPostSignedResponseAndAssertionLoginLogout();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIDPDescriptor() throws Exception {
|
public void testIDPDescriptor() throws Exception {
|
||||||
Client client = ClientBuilder.newClient();
|
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");
|
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig?GLO=true");
|
||||||
checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig/", 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() {
|
public void testPostSignedLoginLogoutTransientNameID() {
|
||||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
|
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
|
||||||
|
@ -523,6 +533,32 @@ public class SamlAdapterTestStrategy extends ExternalResource {
|
||||||
ErrorServlet.authError = null;
|
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 {
|
public void testMetadataPostSignedLoginLogout() throws Exception {
|
||||||
|
|
||||||
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata/");
|
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=="
|
"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/",
|
"name": "http://localhost:8081/sales-post-sig-transient/",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -242,6 +286,23 @@
|
||||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
"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/",
|
"name": "http://localhost:8081/bad-client-sales-post-sig/",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -274,6 +335,7 @@
|
||||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/saml",
|
"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_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/saml",
|
||||||
"saml.server.signature": "true",
|
"saml.server.signature": "true",
|
||||||
|
"saml.assertion.signature": "true",
|
||||||
"saml.signature.algorithm": "RSA_SHA512",
|
"saml.signature.algorithm": "RSA_SHA512",
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.encrypt": "true",
|
"saml.encrypt": "true",
|
||||||
|
|
Loading…
Reference in a new issue