\ No newline at end of file
diff --git a/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml b/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml
index eeb303114d..b112aa09bf 100755
--- a/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml
+++ b/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml
@@ -5,380 +5,471 @@
look like:
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- "connection-pool-size" : 20,
- "disable-trust-manager": false,
- "allow-any-hostname" : false,
- "truststore" : "path/to/truststore.jks",
- "truststore-password" : "geheim",
- "client-keystore" : "path/to/client-keystore.jks",
- "client-keystore-password" : "geheim",
- "client-key-password" : "geheim"
-}]]>
+
+
+
+
+
+
+
+
+
+
+]]>
Some of these configuration switches may be adapter specific and some are common across all adapters.
For Java adapters you can use ${...} enclosure as System property replacement.
- For example ${jboss.server.config.dir}. Also, you can obtain a template
- for this config file from the admin console. Go to the realm and select the application you want a template for.
- Go to the Installation tab and this will provide you with a template that includes
- the public key of the realm.
+ For example ${jboss.server.config.dir}.
+
+ SP Element
+
+ Here is the explanation of the SP element attributes
+
+
+...
+]]>
+
+
+
+ entityID
+
+
+ This is the identifier for this client. The IDP needs this value to determine
+ who the client is that is communicating with it.
+ REQUIRED.
+
+
+
+
+ sslPolicy
+
+
+ This is the SSL policy the adapter will enforce. Valid values are:
+ ALL, EXTERNAL, and NONE. For ALL, all requests must come in via HTTPS. For
+ EXTERNAL, only non-private IP addresses must come over the wire via HTTPS. For
+ NONE, no requests are required to come over via HTTPS. This is
+ OPTIONAL. and defaults to EXTERNAL.
+
+
+
+
+ nameIDPolicyFormat
+
+
+ SAML clients can request a specific NameID Subject format. Fill in this value
+ if you want a specific format. It must be a standard SAML format identifier, i.e.
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ OPTIONAL.. By default, no special format is requested.
+
+
+
+
+ forceAuthentication
+
+
+ SAML clients can request that a user is re-authenticated even if
+ they are already logged in at the IDP. Set this to true if you
+ want this.
+ OPTIONAL.. Set to false by default.
+
+
+
+
+
+
+
+ SP Keys and Key elements
+
+ If the IDP requires that the SP sign all of its requests and/or if the IDP will
+ encrypt assertions, you must define the keys used to do this. For client signed
+ documents you must define both the private and public key or certificate that will
+ be used to sign documents. For encryption, you only have to define the private key
+ that will be used to decrypt.
+
+
+ There are two ways to describe your keys. Either they are stored within a Java KeyStore
+ or you can cut and paste the keys directly within keycloak-saml.xml
+ in the PEM format.
+
+
+
+
+
+
+
+
+
+]]>
+
+
+ The Key element has two optional attributes signing
+ and encryption. When set to true these tell the adapter what the
+ key will be used for. If both attributes are set to true, then the key will be used for both
+ signing documents and decrypting encrypted assertions. You must set at least one of these
+ attributes to true.
+
+
+ KeyStore element
+
+
+
+ file
+
+
+ File path to the key store.
+ OPTIONAL. The file or resource attribute
+ must be set.
+
+
+
+
+ resource
+
+
+ WAR resource path to the KeyStore. This is a path used in method call to ServletContext.getResourceAsStream().
+ OPTIONAL. The file or resource attribute
+ must be set.
+
+
+
+
+ password
+
+
+ The password of the KeyStore
+ REQUIRED.
+
+
+
+
+
+
+
+ You can and must also specify references to your private keys and certificates within
+ the Java KeyStore. The PrivateKey and Certificate
+ elements do this. The alias attribute defines the alias within the
+ KeyStore for the key. For PrivateKey, a password is required to access this key
+ specify that value in the password attribute.
+
+
+
+ Key PEMS
+
+ Within the Key element you alternatively declare your keys and certificates
+ directly using the sub elements PrivateKeyPem, PublicKeyPem, and
+ CertificatePem. The values contained in these elements must conform to the
+ PEM key format. You usually use this option if you are generating keys using openssl
+
+
+
+
+ SP PrincipalNameMapping element
+
+ This element is optional. When creating a Java Principal object that you obtain from
+ methods like HttpServletRequest.getUserPrincipal(), you can define what name that is returned
+ by the Principal.getName() method. The policy attribute defines the
+ policy used to populate this value. The values are FROM_NAME_ID. This policy
+ just grabs whatever the SAML subject value is. The other is FROM_ATTRIBUTE. This will
+ pull the value of Principal.getName() from one of the attributes in the SAML assertion received from the server.
+ The default value is FROM_NAME_ID.
+
+
+
+ RoleIdentifiers element
+
+
+
+
+
+]]>
+
+ This element is optional. It defines which SAML attribute values in the assertion should be
+ mapped to a Java EE role. By default Role attribute values are converted
+ to Java EE roles. Some IDPs send roles via a member or memberOf
+ attribute assertion. You define one or more Attribute elements to specify
+ which SAML attributes must be converted into roles.
+
+
+
+ IDP Element
+
+ Everything in the IDP element describes the settings for the IDP the SP is communicating
+ with.
+
+
+
+...
+]]>
+
+
+
+
+ entityID
+
+
+ This is the issuer ID of the IDP.
+ REQUIRED..
+
+
+
+
+ signaturesRequired
+
+
+ If set to true, the client adapter will sign every document
+ it sends to the IDP. Also, the client will expect that the IDP
+ will be signing an documents sent to it. This switch sets
+ the default for all request and response types, but you will see
+ later that you have some fine grain control over this.
+ OPTIONAL.
+
+
+
+
+ signatureAlgorithm
+
+
+ This is the signature algorithm that the IDP expects signed documents
+ to use
+ OPTIONAL.. The default value is RSA_SHA1, but
+ you can also use RSA_256, RSA_512, and DSA_SHA1.
+
+
+
+
+ signatureCanonicalizationMethod
+
+
+ This is the signature canonicalization method that the IDP expects signed documents
+ to use
+ OPTIONAL.. The default value is http://www.w3.org/2001/10/xml-exc-c14n#
+ and should be good for most IDPs.
+
+
+
+
+
+
+
+ IDP SingleSignOnService sub element
+
+ The SignleSignOnService sub element defines the
+ login SAML endpoint of the IDP.
+
+
+]]>
+
+
+
+ signRequest
+
+
+ Should the client sign authn requests?
+ OPTIONAL.. Defaults to whatever the
+ IDP signaturesRequired element value is.
+
+
+
+
+ validateResponseSignature
+
+
+ Should the client expect the IDP to sign the assertion response document
+ sent back from an auhtn request?
+ OPTIONAL. Defaults to whatever the
+ IDP signaturesRequired element value is.
+
+
+
+
+ requestBinding
+
+
+ This is the SAML binding type used for communicating with the IDP
+ OPTIONAL.. The default value is POST, but
+ you can set it to REDIRECT as well.
+
+
+
+
+ responseBinding
+
+
+ SAML allows the client to request what binding type it wants authn responses
+ to use. The values of this can be POST or REDIRECT
+ OPTIONAL.. The default is that the client will not request
+ a specific binding type for responses.
+
+
+
+
+ bindingUrl
+
+
+ This is the URL for the ID login service that the client will send requests to.
+ REQUIRED..
+
+
+
+
+
+
+ IDP SingleSignOnService sub element
- Here is a description of each item:
+ The SignleSignOnService sub element defines the
+ login SAML endpoint of the IDP.
+
+]]>
- realm
+ signRequest
- Name of the realm representing the users of your distributed applications and services.
- This is
- REQUIRED.
+ Should the client sign logout requests it makes to the IDP?
+ OPTIONAL.. Defaults to whatever the
+ IDP signaturesRequired element value is.
- resource
+ signResponse
- Username of the application. Each application has a username that is used when the
- application connects with the Keycloak server to turn an access code into an access token
- (part of the OAuth 2.0 protocol). This is
- REQUIRED.
+ Should the client sign logout responses it sends to the IDP requests?
+ OPTIONAL.. Defaults to whatever the
+ IDP signaturesRequired element value is.
- realm-public-key
+ validateRequestSignature
- PEM format of public key. You can obtain this from the administration console.
- This is
- REQUIRED.
+ Should the client expect signed logout request documents from the IDP?
+ OPTIONAL. Defaults to whatever the
+ IDP signaturesRequired element value is.
- auth-server-url
+ validateResponseSignature
- The base URL of the Keycloak Server. All other Keycloak pages and REST services are derived
- from this. It is usually of the form https://host:port/auth
- This is
- REQUIRED.
+ Should the client expect signed logout response documents from the IDP?
+ OPTIONAL. Defaults to whatever the
+ IDP signaturesRequired element value is.
- ssl-required
+ requestBinding
- Ensures that all communication to and from the Keycloak server from the adapter is over HTTPS.
- This is OPTIONAL. The default value is
- external
- meaning that HTTPS is required by default for external requests. Valid values are 'all', 'external'
- and 'none'.
+ This is the SAML binding type used for communicating SAML requests to the IDP
+ OPTIONAL.. The default value is POST, but
+ you can set it to REDIRECT as well.
- use-resource-role-mappings
+ responseBinding
- If set to true, the adapter will look inside the token for application level role mappings for
- the
- user. If false, it will look at the realm level for user role mappings.
- This is OPTIONAL. The default value is false.
+ This is the SAML binding type used for communicating SAML responses to the IDP
+ The values of this can be POST or REDIRECT
+ OPTIONAL.. The default value is POST, but
+ you can set it to REDIRECT as well.
- public-client
+ postBindingUrl
- If set to true, the adapter will not send credentials for the client to Keycloak.
- The default value is false.
+ This is the URL for the IDP's logout service when using the POST binding.
+ REQUIRED if using the POST binding at all.
- enable-cors
+ redirectBindingUrl
- This enables CORS support. It will handle CORS preflight requests. It will also look into
- the access token to determine valid origins.
- This is OPTIONAL. The default value is false.
-
-
-
-
- cors-max-age
-
-
- If CORS is enabled, this sets the value of the
- Access-Control-Max-Age
- header.
- This is OPTIONAL. If not set, this header is not returned in CORS
- responses.
-
-
-
-
- cors-allowed-methods
-
-
- If CORS is enabled, this sets the value of the
- Access-Control-Allow-Methods
- header. This should be a comma-separated string.
- This is OPTIONAL. If not set, this header is not returned in CORS
- responses.
-
-
-
-
- cors-allowed-headers
-
-
- If CORS is enabled, this sets the value of the
- Access-Control-Allow-Headers
- header. This should be a comma-separated string.
- This is OPTIONAL. If not set, this header is not returned in CORS
- responses.
-
-
-
-
- bearer-only
-
-
- This tells the adapter to only do bearer token authentication. That is, it will not do
- OAuth 2.0 redirects, but only accept bearer tokens through the
- Authorization
- header.
- This is OPTIONAL. The default value is false.
-
-
-
-
- enable-basic-auth
-
-
- This tells the adapter to also support basic authentication. If this option is enabled,
- then secret must also be provided.
- This is OPTIONAL. The default value is false.
-
-
-
-
- expose-token
-
-
- If true, an authenticated browser client (via a Javascript HTTP invocation)
- can obtain the signed access token via the URL root/k_query_bearer_token.
- This is OPTIONAL. The default value is false.
-
-
-
-
- credentials
-
-
- Specify the credentials of the application. This is an object notation where the key
- is the credential type and the value is the value of the credential type. Currently only
- password
- is supported.
- This is REQUIRED.
-
-
-
-
-
- connection-pool-size
-
-
- Adapters will make separate HTTP invocations to the Keycloak Server to turn an access code
- into an access token. This config option defines how many connections to the Keycloak Server
- should be pooled.
- This is OPTIONAL. The default value is 20.
-
-
-
-
- disable-trust-manager
-
-
- If the Keycloak Server requires HTTPS and this config option is set to true
- you do not have to specify a truststore. While convenient, this setting is not recommended
- as you will not be verifying the host name of the Keycloak Server.
- This is OPTIONAL. The default value is false.
-
-
-
-
- allow-any-hostname
-
-
- If the Keycloak Server requires HTTPS and this config option is set to true
- the Keycloak Server's certificate is validated via the truststore, but host name validation is
- not done. This is not a recommended. This seting may be useful in test environments
- This is OPTIONAL. The default value is false.
-
-
-
-
-
- truststore
-
-
- This setting is for Java adapters. The value is the file path to a Java keystore file. If
- you prefix the path with classpath:, then the truststore will be obtained
- from the deployment's classpath instead.
- Used for outgoing HTTPS communications to the Keycloak server. Client making HTTPS
- requests need a way to verify the host of the server they are talking to. This is
- what the trustore does. The keystore contains one or more trusted
- host certificates or certificate authorities. You can
- create this truststore by extracting the public certificate of the Keycloak server's SSL
- keystore.
- This is
- OPTIONAL
- if
- ssl-required
- is
- none
- or
- disable-trust-manager
- is true.
-
-
-
-
- truststore-password
-
-
- Password for the truststore keystore.
- This is
- REQUIRED
- if
- truststore
- is set.
-
-
-
-
- client-keystore
-
-
- Not supported yet, but we will support in future versions.
-
- This setting is for Java adapters. This is the file path to a Java keystore file.
- This keystore contains client certificate for two-way SSL when the adapter makes
- HTTPS requests to the Keycloak server.
- This is OPTIONAL.
-
-
-
-
- client-keystore-password
-
-
- Not supported yet, but we will support in future versions.
- Password for the client keystore.
- This is
- REQUIRED
- if
- client-keystore
- is set.
-
-
-
-
- client-key-password
-
-
- Not supported yet, but we will support in future versions.
- Password for the client's key.
- This is
- REQUIRED
- if
- client-keystore
- is set.
-
-
-
-
- auth-server-url-for-backend-requests
-
-
- Alternative location of auth-server-url used just for backend requests. It must be absolute URI. Useful
- especially in cluster (see Relative URI Optimization) or if you would like to use https for browser requests
- but stick with http for backend requests etc.
-
-
-
-
- always-refresh-token
-
-
- If true, Keycloak will refresh token in every request. More info in Refresh token in each request .
-
-
-
-
- register-node-at-startup
-
-
- If true, then adapter will send registration request to Keycloak. It's false
- by default and useful just in cluster (See Registration of application nodes to Keycloak)
-
-
-
-
- register-node-period
-
-
- Period for re-registration adapter to Keycloak. Useful in cluster. See Registration of application nodes to Keycloak for details.
-
-
-
-
- token-store
-
-
- Possible values are session and cookie. Default is session,
- which means that adapter stores account info in HTTP Session. Alternative cookie means storage of info in cookie.
- See Stateless token store for details.
-
-
-
-
- principal-attribute
-
-
- OpenID Connection ID Token attribute to populate the UserPrincipal name with. If token attribute is null, defaults to sub.
- Possible values are sub, preferred_username, email, name, nickname, given_name, family_name.
+ This is the URL for the IDP's logout service when using the REDIRECT binding.
+ REQUIRED if using the REDIRECT binding at all.
+
+
+ IDP Keys subelement
+
+ The Keys sub element of IDP is only used to define the certificate or
+ public key to use to verify documents signed by the IDP. It is defined
+ in the same way as the SP's Key's element. But
+ again, you only have to define one certificate or public key reference.
+
+
+
+
diff --git a/examples/saml/post-with-encryption/src/main/webapp/WEB-INF/keycloak-saml.xml b/examples/saml/post-with-encryption/src/main/webapp/WEB-INF/keycloak-saml.xml
index c3132e2168..a094acf3f4 100755
--- a/examples/saml/post-with-encryption/src/main/webapp/WEB-INF/keycloak-saml.xml
+++ b/examples/saml/post-with-encryption/src/main/webapp/WEB-INF/keycloak-saml.xml
@@ -13,9 +13,9 @@
-
+
-
+
-
+
-
+
-
+
-
+
${project.version}
zip
+
+ org.keycloak
+ keycloak-saml-tomcat6-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-tomcat7-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-tomcat8-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-jetty81-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-jetty92-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-as7-adapter-dist
+ ${project.version}
+ zip
+
+
+ org.keycloak
+ keycloak-saml-eap6-adapter-dist
+ ${project.version}
+ zip
+ org.keycloakkeycloak-testsuite-integration
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
index 681e405a99..258f14bca3 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
@@ -67,8 +67,7 @@ public interface SamlDeployment {
enum PrincipalNamePolicy {
FROM_NAME_ID,
- FROM_ATTRIBUTE_NAME,
- FROM_FRIENDLY_ATTRIBUTE_NAME
+ FROM_ATTRIBUTE
}
PrincipalNamePolicy getPrincipalNamePolicy();
String getPrincipalAttributeName();
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
index fc08e449a3..d1aaea9c66 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
@@ -24,16 +24,16 @@ public class IDPXmlParser extends AbstractParser {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
IDP idp = new IDP();
- String entityID = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
+ String entityID = SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
if (entityID == null) {
throw new ParsingException("entityID must be set on IDP");
}
idp.setEntityID(entityID);
- boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
- idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
- idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
+ boolean signaturesRequired = SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
+ idp.setSignatureCanonicalizationMethod(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
+ idp.setSignatureAlgorithm(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
@@ -73,25 +73,25 @@ public class IDPXmlParser extends AbstractParser {
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- slo.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
- slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
- slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
- slo.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
- slo.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
- slo.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
- slo.setPostBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
- slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
+ slo.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
+ slo.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
+ slo.setValidateRequestSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
+ slo.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
+ slo.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
+ slo.setSignResponse(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
+ slo.setPostBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
+ slo.setRedirectBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
return slo;
}
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- sso.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
- sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
- sso.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
- sso.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
- sso.setBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
+ sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
+ sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
+ 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));
return sso;
}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
index 6fbd8d037f..0308a56a22 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
@@ -7,8 +7,6 @@ import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
@@ -24,8 +22,8 @@ public class KeyXmlParser extends AbstractParser {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEY_ELEMENT);
Key key = new Key();
- key.setSigning(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
- key.setEncryption(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.ENCRYPTION_ATTR));
+ key.setSigning(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
+ key.setEncryption(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.ENCRYPTION_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
@@ -46,13 +44,13 @@ public class KeyXmlParser extends AbstractParser {
key.setKeystore(parseKeyStore(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- key.setCertificatePem(StaxParserUtil.getElementText(xmlEventReader));
+ key.setCertificatePem(SPXmlParser.getElementText(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- key.setPublicKeyPem(StaxParserUtil.getElementText(xmlEventReader));
+ key.setPublicKeyPem(SPXmlParser.getElementText(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- key.setPrivateKeyPem(StaxParserUtil.getElementText(xmlEventReader));
+ key.setPrivateKeyPem(SPXmlParser.getElementText(xmlEventReader));
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
@@ -65,14 +63,14 @@ public class KeyXmlParser extends AbstractParser {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_STORE_ELEMENT);
Key.KeyStoreConfig keyStore = new Key.KeyStoreConfig();
- keyStore.setType(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
- keyStore.setAlias(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
- keyStore.setFile(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
- keyStore.setResource(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
+ keyStore.setType(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
+ keyStore.setAlias(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
+ keyStore.setFile(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
+ keyStore.setResource(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
if (keyStore.getFile() == null && keyStore.getResource() == null) {
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
}
- keyStore.setPassword(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
+ keyStore.setPassword(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
if (keyStore.getPassword() == null) {
throw new ParsingException("KeyStore element must have the password attribute set");
}
@@ -97,19 +95,19 @@ public class KeyXmlParser extends AbstractParser {
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- keyStore.setCertificateAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
+ keyStore.setCertificateAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
if (keyStore.getCertificateAlias() == null) {
throw new ParsingException("KeyStore Certificate element must have the alias attribute set");
}
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- keyStore.setPrivateKeyAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
+ keyStore.setPrivateKeyAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
if (keyStore.getPrivateKeyAlias() == null) {
throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
}
- keyStore.setPrivateKeyPassword(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
+ keyStore.setPrivateKeyPassword(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
if (keyStore.getPrivateKeyPassword() == null) {
throw new ParsingException("KeyStore PrivateKey element must have the password attribute set");
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
index f0104707b4..34b924d1ae 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
@@ -6,9 +6,11 @@ import org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.util.StringPropertyReplacer;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
@@ -23,21 +25,44 @@ import java.util.Set;
*/
public class SPXmlParser extends AbstractParser {
+ public static String getAttributeValue(StartElement startElement, String tag) {
+ String str = StaxParserUtil.getAttributeValue(startElement, tag);
+ if (str != null) return StringPropertyReplacer.replaceProperties(str);
+ else return str;
+ }
+
+ public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) {
+ String result = getAttributeValue(startElement, tag);
+ if (result == null) return defaultValue;
+ return Boolean.valueOf(result);
+ }
+
+ public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
+ return getBooleanAttributeValue(startElement, tag, false);
+ }
+
+ public static String getElementText(XMLEventReader xmlEventReader) throws ParsingException {
+ String result = StaxParserUtil.getElementText(xmlEventReader);
+ if (result != null) result = StringPropertyReplacer.replaceProperties(result);
+ return result;
+ }
+
+
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.SP_ELEMENT);
SP sp = new SP();
- String entityID = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
+ String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
if (entityID == null) {
throw new ParsingException("entityID must be set on SP");
}
sp.setEntityID(entityID);
- sp.setSslPolicy(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR));
- sp.setLogoutPage(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR));
- sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR));
- sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR));
+ sp.setSslPolicy(getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR));
+ sp.setLogoutPage(getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR));
+ sp.setNameIDPolicyFormat(getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR));
+ sp.setForceAuthentication(getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
@@ -60,12 +85,12 @@ public class SPXmlParser extends AbstractParser {
sp.setKeys(keys);
} else if (tag.equals(ConfigXmlConstants.PRINCIPAL_NAME_MAPPING_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- String policy = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
+ String policy = getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
if (policy == null) {
throw new ParsingException("PrincipalNameMapping element must have the policy attribute set");
}
- String attribute = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
+ String attribute = getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
mapping.setPolicy(policy);
mapping.setAttributeName(attribute);
@@ -107,7 +132,7 @@ public class SPXmlParser extends AbstractParser {
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
- String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
+ String attributeValue = getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
if (attributeValue == null) {
throw new ParsingException("RoleMapping Attribute element must have the name attribute set");
diff --git a/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
index b9e0799e97..534c9aef56 100755
--- a/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
+++ b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
@@ -25,7 +25,7 @@
-
+
@@ -70,7 +70,7 @@
-
+
diff --git a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
index 5f881975e7..ef910dceca 100755
--- a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
+++ b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
@@ -20,9 +20,9 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+