KEYCLOAK-6470 Refactor SAML adapter parsers
This commit is contained in:
parent
d70e4740fc
commit
1f20c03afa
35 changed files with 1346 additions and 726 deletions
|
@ -71,6 +71,11 @@
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-all</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
|
|
|
@ -27,35 +27,36 @@ import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
|
||||||
*/
|
*/
|
||||||
public class IDP implements Serializable {
|
public class IDP implements Serializable {
|
||||||
public static class SingleSignOnService implements Serializable {
|
public static class SingleSignOnService implements Serializable {
|
||||||
private boolean signRequest;
|
private Boolean signRequest;
|
||||||
private boolean validateResponseSignature;
|
private Boolean validateResponseSignature;
|
||||||
private String requestBinding;
|
private String requestBinding;
|
||||||
private String responseBinding;
|
private String responseBinding;
|
||||||
private String bindingUrl;
|
private String bindingUrl;
|
||||||
private String assertionConsumerServiceUrl;
|
private String assertionConsumerServiceUrl;
|
||||||
private boolean validateAssertionSignature;
|
private Boolean validateAssertionSignature;
|
||||||
|
private boolean signaturesRequired = false;
|
||||||
|
|
||||||
public boolean isSignRequest() {
|
public boolean isSignRequest() {
|
||||||
return signRequest;
|
return signRequest == null ? signaturesRequired : signRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSignRequest(boolean signRequest) {
|
public void setSignRequest(Boolean signRequest) {
|
||||||
this.signRequest = signRequest;
|
this.signRequest = signRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidateResponseSignature() {
|
public boolean isValidateResponseSignature() {
|
||||||
return validateResponseSignature;
|
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
public void setValidateResponseSignature(Boolean validateResponseSignature) {
|
||||||
this.validateResponseSignature = validateResponseSignature;
|
this.validateResponseSignature = validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidateAssertionSignature() {
|
public boolean isValidateAssertionSignature() {
|
||||||
return validateAssertionSignature;
|
return validateAssertionSignature == null ? false : validateAssertionSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
public void setValidateAssertionSignature(Boolean validateAssertionSignature) {
|
||||||
this.validateAssertionSignature = validateAssertionSignature;
|
this.validateAssertionSignature = validateAssertionSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,47 +91,52 @@ public class IDP implements Serializable {
|
||||||
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
||||||
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSignaturesRequired(boolean signaturesRequired) {
|
||||||
|
this.signaturesRequired = signaturesRequired;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SingleLogoutService implements Serializable {
|
public static class SingleLogoutService implements Serializable {
|
||||||
private boolean signRequest;
|
private Boolean signRequest;
|
||||||
private boolean signResponse;
|
private Boolean signResponse;
|
||||||
private boolean validateRequestSignature;
|
private Boolean validateRequestSignature;
|
||||||
private boolean validateResponseSignature;
|
private Boolean validateResponseSignature;
|
||||||
private String requestBinding;
|
private String requestBinding;
|
||||||
private String responseBinding;
|
private String responseBinding;
|
||||||
private String postBindingUrl;
|
private String postBindingUrl;
|
||||||
private String redirectBindingUrl;
|
private String redirectBindingUrl;
|
||||||
|
private boolean signaturesRequired = false;
|
||||||
|
|
||||||
public boolean isSignRequest() {
|
public boolean isSignRequest() {
|
||||||
return signRequest;
|
return signRequest == null ? signaturesRequired : signRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSignRequest(boolean signRequest) {
|
public void setSignRequest(Boolean signRequest) {
|
||||||
this.signRequest = signRequest;
|
this.signRequest = signRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSignResponse() {
|
public boolean isSignResponse() {
|
||||||
return signResponse;
|
return signResponse == null ? signaturesRequired : signResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSignResponse(boolean signResponse) {
|
public void setSignResponse(Boolean signResponse) {
|
||||||
this.signResponse = signResponse;
|
this.signResponse = signResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidateRequestSignature() {
|
public boolean isValidateRequestSignature() {
|
||||||
return validateRequestSignature;
|
return validateRequestSignature == null ? signaturesRequired : validateRequestSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValidateRequestSignature(boolean validateRequestSignature) {
|
public void setValidateRequestSignature(Boolean validateRequestSignature) {
|
||||||
this.validateRequestSignature = validateRequestSignature;
|
this.validateRequestSignature = validateRequestSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidateResponseSignature() {
|
public boolean isValidateResponseSignature() {
|
||||||
return validateResponseSignature;
|
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
public void setValidateResponseSignature(Boolean validateResponseSignature) {
|
||||||
this.validateResponseSignature = validateResponseSignature;
|
this.validateResponseSignature = validateResponseSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +171,10 @@ public class IDP implements Serializable {
|
||||||
public void setRedirectBindingUrl(String redirectBindingUrl) {
|
public void setRedirectBindingUrl(String redirectBindingUrl) {
|
||||||
this.redirectBindingUrl = redirectBindingUrl;
|
this.redirectBindingUrl = redirectBindingUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSignaturesRequired(boolean signaturesRequired) {
|
||||||
|
this.signaturesRequired = signaturesRequired;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HttpClientConfig implements AdapterHttpClientConfig {
|
public static class HttpClientConfig implements AdapterHttpClientConfig {
|
||||||
|
@ -258,6 +268,7 @@ public class IDP implements Serializable {
|
||||||
private SingleLogoutService singleLogoutService;
|
private SingleLogoutService singleLogoutService;
|
||||||
private List<Key> keys;
|
private List<Key> keys;
|
||||||
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
|
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||||
|
private boolean signaturesRequired = false;
|
||||||
|
|
||||||
public String getEntityID() {
|
public String getEntityID() {
|
||||||
return entityID;
|
return entityID;
|
||||||
|
@ -273,6 +284,9 @@ public class IDP implements Serializable {
|
||||||
|
|
||||||
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
||||||
this.singleSignOnService = singleSignOnService;
|
this.singleSignOnService = singleSignOnService;
|
||||||
|
if (singleSignOnService != null) {
|
||||||
|
singleSignOnService.setSignaturesRequired(signaturesRequired);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingleLogoutService getSingleLogoutService() {
|
public SingleLogoutService getSingleLogoutService() {
|
||||||
|
@ -281,6 +295,9 @@ public class IDP implements Serializable {
|
||||||
|
|
||||||
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
||||||
this.singleLogoutService = singleLogoutService;
|
this.singleLogoutService = singleLogoutService;
|
||||||
|
if (singleLogoutService != null) {
|
||||||
|
singleLogoutService.setSignaturesRequired(signaturesRequired);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Key> getKeys() {
|
public List<Key> getKeys() {
|
||||||
|
@ -315,4 +332,12 @@ public class IDP implements Serializable {
|
||||||
this.httpClientConfig = httpClientConfig;
|
this.httpClientConfig = httpClientConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSignaturesRequired() {
|
||||||
|
return signaturesRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignaturesRequired(boolean signaturesRequired) {
|
||||||
|
this.signaturesRequired = signaturesRequired;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,16 +114,16 @@ public class Key implements Serializable {
|
||||||
return signing;
|
return signing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSigning(boolean signing) {
|
public void setSigning(Boolean signing) {
|
||||||
this.signing = signing;
|
this.signing = signing != null && signing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEncryption() {
|
public boolean isEncryption() {
|
||||||
return encryption;
|
return encryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEncryption(boolean encryption) {
|
public void setEncryption(Boolean encryption) {
|
||||||
this.encryption = encryption;
|
this.encryption = encryption != null && encryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyStoreConfig getKeystore() {
|
public KeyStoreConfig getKeystore() {
|
||||||
|
|
|
@ -26,13 +26,14 @@ import java.util.List;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class KeycloakSamlAdapter implements Serializable {
|
public class KeycloakSamlAdapter implements Serializable {
|
||||||
private List<SP> sps = new LinkedList<>();
|
private final List<SP> sps = new LinkedList<>();
|
||||||
|
|
||||||
public List<SP> getSps() {
|
public List<SP> getSps() {
|
||||||
return sps;
|
return sps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSps(List<SP> sps) {
|
public void addSp(SP sp) {
|
||||||
this.sps = sps;
|
sps.add(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,24 +80,24 @@ public class SP implements Serializable {
|
||||||
return forceAuthentication;
|
return forceAuthentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForceAuthentication(boolean forceAuthentication) {
|
public void setForceAuthentication(Boolean forceAuthentication) {
|
||||||
this.forceAuthentication = forceAuthentication;
|
this.forceAuthentication = forceAuthentication != null && forceAuthentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIsPassive() {
|
public boolean isIsPassive() {
|
||||||
return isPassive;
|
return isPassive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsPassive(boolean isPassive) {
|
public void setIsPassive(Boolean isPassive) {
|
||||||
this.isPassive = isPassive;
|
this.isPassive = isPassive != null && isPassive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTurnOffChangeSessionIdOnLogin() {
|
public boolean isTurnOffChangeSessionIdOnLogin() {
|
||||||
return turnOffChangeSessionIdOnLogin;
|
return turnOffChangeSessionIdOnLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
|
public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) {
|
||||||
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
|
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin != null && turnOffChangeSessionIdOnLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Key> getKeys() {
|
public List<Key> getKeys() {
|
||||||
|
@ -152,7 +152,7 @@ public class SP implements Serializable {
|
||||||
return autodetectBearerOnly;
|
return autodetectBearerOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
|
public void setAutodetectBearerOnly(Boolean autodetectBearerOnly) {
|
||||||
this.autodetectBearerOnly = autodetectBearerOnly;
|
this.autodetectBearerOnly = autodetectBearerOnly != null && autodetectBearerOnly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.parsers.AbstractStaxParser;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractKeycloakSamlAdapterV1Parser<T> extends AbstractStaxParser<T, KeycloakSamlAdapterV1QNames> {
|
||||||
|
|
||||||
|
protected static final QNameEnumLookup<KeycloakSamlAdapterV1QNames> LOOKUP = new QNameEnumLookup(KeycloakSamlAdapterV1QNames.values());
|
||||||
|
|
||||||
|
private static final Set<String> ALTERNATE_NAMESPACES = Collections.singleton(XMLConstants.NULL_NS_URI);
|
||||||
|
|
||||||
|
public AbstractKeycloakSamlAdapterV1Parser(KeycloakSamlAdapterV1QNames expectedStartElement) {
|
||||||
|
super(expectedStartElement.getQName(), KeycloakSamlAdapterV1QNames.UNKNOWN_ELEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeycloakSamlAdapterV1QNames getElementFromName(QName name) {
|
||||||
|
return (ALTERNATE_NAMESPACES.contains(name.getNamespaceURI()))
|
||||||
|
? LOOKUP.from(new QName(KeycloakSamlAdapterV1QNames.NS_URI, name.getLocalPart()))
|
||||||
|
: LOOKUP.from(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void validateStartElement(StartElement startElement) {
|
||||||
|
QName name = startElement.getName();
|
||||||
|
QName validatedQName = ALTERNATE_NAMESPACES.contains(name.getNamespaceURI())
|
||||||
|
? new QName(name.getNamespaceURI(), expectedStartElement.getLocalPart())
|
||||||
|
: expectedStartElement;
|
||||||
|
StaxParserUtil.validate(startElement, validatedQName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class ConfigXmlConstants {
|
|
||||||
public static final String KEYCLOAK_SAML_ADAPTER = "keycloak-saml-adapter";
|
|
||||||
public static final String SP_ELEMENT = "SP";
|
|
||||||
public static final String ENTITY_ID_ATTR = "entityID";
|
|
||||||
public static final String SSL_POLICY_ATTR = "sslPolicy";
|
|
||||||
public static final String NAME_ID_POLICY_FORMAT_ATTR = "nameIDPolicyFormat";
|
|
||||||
public static final String FORCE_AUTHENTICATION_ATTR = "forceAuthentication";
|
|
||||||
public static final String IS_PASSIVE_ATTR = "isPassive";
|
|
||||||
public static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR = "turnOffChangeSessionIdOnLogin";
|
|
||||||
public static final String SIGNATURE_ALGORITHM_ATTR = "signatureAlgorithm";
|
|
||||||
public static final String SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod";
|
|
||||||
public static final String LOGOUT_PAGE_ATTR = "logoutPage";
|
|
||||||
public static final String AUTODETECT_BEARER_ONLY_ATTR = "autodetectBearerOnly";
|
|
||||||
|
|
||||||
public static final String KEYS_ELEMENT = "Keys";
|
|
||||||
public static final String KEY_ELEMENT = "Key";
|
|
||||||
public static final String SIGNING_ATTR = "signing";
|
|
||||||
public static final String ENCRYPTION_ATTR = "encryption";
|
|
||||||
public static final String CERTIFICATE_PEM_ELEMENT = "CertificatePem";
|
|
||||||
public static final String PRIVATE_KEY_PEM_ELEMENT = "PrivateKeyPem";
|
|
||||||
public static final String PUBLIC_KEY_PEM_ELEMENT = "PublicKeyPem";
|
|
||||||
public static final String FILE_ATTR = "file";
|
|
||||||
public static final String TYPE_ATTR = "type";
|
|
||||||
public static final String RESOURCE_ATTR = "resource";
|
|
||||||
public static final String PASSWORD_ATTR = "password";
|
|
||||||
public static final String ALIAS_ATTR = "alias";
|
|
||||||
public static final String KEYS_STORE_ELEMENT = "KeyStore";
|
|
||||||
public static final String CERTIFICATE_ELEMENT = "Certificate";
|
|
||||||
public static final String PRIVATE_KEY_ELEMENT = "PrivateKey";
|
|
||||||
|
|
||||||
public static final String PRINCIPAL_NAME_MAPPING_ELEMENT = "PrincipalNameMapping";
|
|
||||||
public static final String POLICY_ATTR = "policy";
|
|
||||||
public static final String ATTRIBUTE_ATTR = "attribute";
|
|
||||||
|
|
||||||
public static final String ROLE_IDENTIFIERS_ELEMENT = "RoleIdentifiers";
|
|
||||||
public static final String ATTRIBUTE_ELEMENT = "Attribute";
|
|
||||||
public static final String NAME_ATTR = "name";
|
|
||||||
|
|
||||||
public static final String IDP_ELEMENT = "IDP";
|
|
||||||
public static final String SIGNATURES_REQUIRED_ATTR = "signaturesRequired";
|
|
||||||
public static final String SINGLE_SIGN_ON_SERVICE_ELEMENT = "SingleSignOnService";
|
|
||||||
public static final String SINGLE_LOGOUT_SERVICE_ELEMENT = "SingleLogoutService";
|
|
||||||
public static final String SIGN_REQUEST_ATTR = "signRequest";
|
|
||||||
public static final String SIGN_RESPONSE_ATTR = "signResponse";
|
|
||||||
public static final String REQUEST_BINDING_ATTR = "requestBinding";
|
|
||||||
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";
|
|
||||||
public static final String ASSERTION_CONSUMER_SERVICE_URL_ATTR = "assertionConsumerServiceUrl";
|
|
||||||
|
|
||||||
public static final String HTTP_CLIENT_ELEMENT = "HttpClient";
|
|
||||||
public static final String ALLOW_ANY_HOSTNAME_ATTR = "allowAnyHostname";
|
|
||||||
public static final String CLIENT_KEYSTORE_ATTR = "clientKeystore";
|
|
||||||
public static final String CLIENT_KEYSTORE_PASSWORD_ATTR = "clientKeystorePassword";
|
|
||||||
public static final String CONNECTION_POOL_SIZE_ATTR = "connectionPoolSize";
|
|
||||||
public static final String DISABLE_TRUST_MANAGER_ATTR = "disableTrustManager";
|
|
||||||
public static final String PROXY_URL_ATTR = "proxyUrl";
|
|
||||||
public static final String TRUSTSTORE_ATTR = "truststore";
|
|
||||||
public static final String TRUSTSTORE_PASSWORD_ATTR = "truststorePassword";
|
|
||||||
|
|
||||||
}
|
|
|
@ -59,7 +59,7 @@ public class DeploymentBuilder {
|
||||||
idp.setSingleSignOnService(sso);
|
idp.setSingleSignOnService(sso);
|
||||||
idp.setSingleLogoutService(slo);
|
idp.setSingleLogoutService(slo);
|
||||||
|
|
||||||
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
|
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter) KeycloakSamlAdapterParser.getInstance().parse(xml);
|
||||||
SP sp = adapter.getSps().get(0);
|
SP sp = adapter.getSps().get(0);
|
||||||
deployment.setConfigured(true);
|
deployment.setConfigured(true);
|
||||||
deployment.setEntityID(sp.getEntityID());
|
deployment.setEntityID(sp.getEntityID());
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class HttpClientParser extends AbstractKeycloakSamlAdapterV1Parser<HttpClientConfig> {
|
||||||
|
|
||||||
|
private static final HttpClientParser INSTANCE = new HttpClientParser();
|
||||||
|
|
||||||
|
private HttpClientParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.HTTP_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpClientParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpClientConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final HttpClientConfig config = new HttpClientConfig();
|
||||||
|
|
||||||
|
final Boolean allowAnyHostname = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALLOW_ANY_HOSTNAME);
|
||||||
|
config.setAllowAnyHostname(allowAnyHostname == null ? false : allowAnyHostname);
|
||||||
|
config.setClientKeystore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE));
|
||||||
|
config.setClientKeystorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE_PASSWORD));
|
||||||
|
final Integer connPoolSize = StaxParserUtil.getIntegerAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CONNECTION_POOL_SIZE);
|
||||||
|
config.setConnectionPoolSize(connPoolSize == null ? 0 : connPoolSize);
|
||||||
|
final Boolean disableTrustManager = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_DISABLE_TRUST_MANAGER);
|
||||||
|
config.setDisableTrustManager(disableTrustManager == null ? false : disableTrustManager);
|
||||||
|
config.setProxyUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PROXY_URL));
|
||||||
|
config.setTruststore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE));
|
||||||
|
config.setTruststorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE_PASSWORD));
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, HttpClientConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
|
||||||
|
|
||||||
import org.keycloak.adapters.saml.config.IDP;
|
|
||||||
import org.keycloak.adapters.saml.config.Key;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
|
||||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLEventReader;
|
|
||||||
import javax.xml.stream.events.EndElement;
|
|
||||||
import javax.xml.stream.events.StartElement;
|
|
||||||
import javax.xml.stream.events.XMLEvent;
|
|
||||||
import java.util.List;
|
|
||||||
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
|
|
||||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getAttributeValue;
|
|
||||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getBooleanAttributeValue;
|
|
||||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getIntegerAttributeValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class IDPXmlParser extends AbstractParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
|
|
||||||
IDP idp = new IDP();
|
|
||||||
String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
|
||||||
if (entityID == null) {
|
|
||||||
throw new ParsingException("entityID must be set on IDP");
|
|
||||||
|
|
||||||
}
|
|
||||||
idp.setEntityID(entityID);
|
|
||||||
|
|
||||||
boolean signaturesRequired = getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
|
|
||||||
idp.setSignatureCanonicalizationMethod(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
|
||||||
idp.setSignatureAlgorithm(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.IDP_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
|
|
||||||
IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired);
|
|
||||||
idp.setSingleSignOnService(sso);
|
|
||||||
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
|
|
||||||
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
|
|
||||||
idp.setSingleLogoutService(slo);
|
|
||||||
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.HTTP_CLIENT_ELEMENT)) {
|
|
||||||
HttpClientConfig config = parseHttpClientElement(xmlEventReader);
|
|
||||||
idp.setHttpClientConfig(config);
|
|
||||||
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
|
|
||||||
KeysXmlParser parser = new KeysXmlParser();
|
|
||||||
List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
|
|
||||||
idp.setKeys(keys);
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return idp;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
|
|
||||||
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
slo.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
|
||||||
slo.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
|
||||||
slo.setValidateRequestSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
|
|
||||||
slo.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
|
||||||
slo.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
|
||||||
slo.setSignResponse(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
|
|
||||||
slo.setPostBindingUrl(getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
|
|
||||||
slo.setRedirectBindingUrl(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(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
|
||||||
sso.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
|
||||||
sso.setValidateAssertionSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
|
|
||||||
sso.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
|
||||||
sso.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
|
||||||
sso.setBindingUrl(getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
|
||||||
sso.setAssertionConsumerServiceUrl(getAttributeValue(element, ConfigXmlConstants.ASSERTION_CONSUMER_SERVICE_URL_ATTR));
|
|
||||||
return sso;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpClientConfig parseHttpClientElement(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.HTTP_CLIENT_ELEMENT);
|
|
||||||
HttpClientConfig config = new HttpClientConfig();
|
|
||||||
|
|
||||||
config.setAllowAnyHostname(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
|
|
||||||
config.setClientKeystore(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_ATTR));
|
|
||||||
config.setClientKeystorePassword(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_PASSWORD_ATTR));
|
|
||||||
config.setConnectionPoolSize(getIntegerAttributeValue(startElement, ConfigXmlConstants.CONNECTION_POOL_SIZE_ATTR, 0));
|
|
||||||
config.setDisableTrustManager(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
|
|
||||||
config.setProxyUrl(getAttributeValue(startElement, ConfigXmlConstants.PROXY_URL_ATTR));
|
|
||||||
config.setTruststore(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_ATTR));
|
|
||||||
config.setTruststorePassword(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_PASSWORD_ATTR));
|
|
||||||
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.IDP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class IdpParser extends AbstractKeycloakSamlAdapterV1Parser<IDP> {
|
||||||
|
|
||||||
|
private static final IdpParser INSTANCE = new IdpParser();
|
||||||
|
|
||||||
|
private IdpParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.IDP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdpParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IDP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final IDP idp = new IDP();
|
||||||
|
|
||||||
|
idp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
|
||||||
|
|
||||||
|
Boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURES_REQUIRED);
|
||||||
|
idp.setSignaturesRequired(signaturesRequired == null ? false : signaturesRequired);
|
||||||
|
idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_CANONICALIZATION_METHOD));
|
||||||
|
idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_ALGORITHM));
|
||||||
|
|
||||||
|
return idp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, IDP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case HTTP_CLIENT:
|
||||||
|
target.setHttpClientConfig(HttpClientParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEYS:
|
||||||
|
target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SINGLE_SIGN_ON_SERVICE:
|
||||||
|
target.setSingleSignOnService(SingleSignOnServiceParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SINGLE_LOGOUT_SERVICE:
|
||||||
|
target.setSingleLogoutService(SingleLogoutServiceParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.Key;
|
||||||
|
import org.keycloak.common.util.StringPropertyReplacer;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class KeyParser extends AbstractKeycloakSamlAdapterV1Parser<Key> {
|
||||||
|
|
||||||
|
private static final KeyParser INSTANCE = new KeyParser();
|
||||||
|
|
||||||
|
private KeyParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Key instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
Key key = new Key();
|
||||||
|
key.setSigning(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNING));
|
||||||
|
key.setEncryption(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENCRYPTION));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, Key target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
String value;
|
||||||
|
switch (element) {
|
||||||
|
case KEY_STORE:
|
||||||
|
target.setKeystore(KeyStoreParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CERTIFICATE_PEM:
|
||||||
|
StaxParserUtil.advance(xmlEventReader);
|
||||||
|
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||||
|
target.setCertificatePem(StringPropertyReplacer.replaceProperties(value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUBLIC_KEY_PEM:
|
||||||
|
StaxParserUtil.advance(xmlEventReader);
|
||||||
|
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||||
|
target.setPublicKeyPem(StringPropertyReplacer.replaceProperties(value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRIVATE_KEY_PEM:
|
||||||
|
StaxParserUtil.advance(xmlEventReader);
|
||||||
|
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||||
|
target.setPrivateKeyPem(StringPropertyReplacer.replaceProperties(value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.Key;
|
||||||
|
import org.keycloak.adapters.saml.config.Key.KeyStoreConfig;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class KeyStoreParser extends AbstractKeycloakSamlAdapterV1Parser<KeyStoreConfig> {
|
||||||
|
|
||||||
|
private static final KeyStoreParser INSTANCE = new KeyStoreParser();
|
||||||
|
|
||||||
|
private KeyStoreParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.KEY_STORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyStoreParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyStoreConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final KeyStoreConfig keyStore = new Key.KeyStoreConfig();
|
||||||
|
keyStore.setType(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TYPE));
|
||||||
|
keyStore.setAlias(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||||
|
keyStore.setFile(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FILE));
|
||||||
|
keyStore.setResource(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESOURCE));
|
||||||
|
keyStore.setPassword(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
|
||||||
|
|
||||||
|
if (keyStore.getFile() == null && keyStore.getResource() == null) {
|
||||||
|
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, KeyStoreConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case CERTIFICATE:
|
||||||
|
target.setCertificateAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRIVATE_KEY:
|
||||||
|
target.setPrivateKeyAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||||
|
target.setPrivateKeyPassword(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,141 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
|
||||||
|
|
||||||
import org.keycloak.adapters.saml.config.Key;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
|
||||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLEventReader;
|
|
||||||
import javax.xml.stream.events.EndElement;
|
|
||||||
import javax.xml.stream.events.StartElement;
|
|
||||||
import javax.xml.stream.events.XMLEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class KeyXmlParser extends AbstractParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEY_ELEMENT);
|
|
||||||
Key key = new Key();
|
|
||||||
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)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.KEY_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
throw logger.parserUnknownEndElement(endElementName, xmlEvent.getLocation());
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT)) {
|
|
||||||
key.setKeystore(parseKeyStore(xmlEventReader));
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
key.setCertificatePem(SPXmlParser.getElementText(xmlEventReader));
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
key.setPublicKeyPem(SPXmlParser.getElementText(xmlEventReader));
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
key.setPrivateKeyPem(SPXmlParser.getElementText(xmlEventReader));
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Key.KeyStoreConfig parseKeyStore(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_STORE_ELEMENT);
|
|
||||||
Key.KeyStoreConfig keyStore = new Key.KeyStoreConfig();
|
|
||||||
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(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
|
|
||||||
if (keyStore.getPassword() == null) {
|
|
||||||
throw new ParsingException("KeyStore element must have the password attribute set");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
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(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
|
|
||||||
if (keyStore.getPrivateKeyAlias() == null) {
|
|
||||||
throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
|
|
||||||
|
|
||||||
}
|
|
||||||
keyStore.setPrivateKeyPassword(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
|
|
||||||
if (keyStore.getPrivateKeyPassword() == null) {
|
|
||||||
throw new ParsingException("KeyStore PrivateKey element must have the password attribute set");
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return keyStore;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.ErrorCodes;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.parsers.AbstractParser;
|
||||||
|
import org.keycloak.saml.common.parsers.StaxParser;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
import javax.xml.stream.events.XMLEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author hmlnarik
|
||||||
|
*/
|
||||||
|
public class KeycloakSamlAdapterParser extends AbstractParser {
|
||||||
|
|
||||||
|
private interface ParserFactory {
|
||||||
|
public StaxParser create();
|
||||||
|
}
|
||||||
|
private static final Map<QName, ParserFactory> PARSERS = new HashMap<QName, ParserFactory>();
|
||||||
|
|
||||||
|
// No-namespace variant
|
||||||
|
private static final QName ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1 = new QName(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName().getLocalPart());
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSERS.put(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName(), new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
|
||||||
|
PARSERS.put(ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1, new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final KeycloakSamlAdapterParser INSTANCE = new KeycloakSamlAdapterParser();
|
||||||
|
|
||||||
|
public static KeycloakSamlAdapterParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeycloakSamlAdapterParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see {@link org.keycloak.saml.common.parsers.ParserNamespaceSupport#parse(XMLEventReader)}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
||||||
|
while (xmlEventReader.hasNext()) {
|
||||||
|
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||||
|
|
||||||
|
if (xmlEvent instanceof StartElement) {
|
||||||
|
StartElement startElement = (StartElement) xmlEvent;
|
||||||
|
final QName name = startElement.getName();
|
||||||
|
|
||||||
|
ParserFactory pf = PARSERS.get(name);
|
||||||
|
if (pf == null) {
|
||||||
|
throw logger.parserException(new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + name + "::location="
|
||||||
|
+ startElement.getLocation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pf.create().parse(xmlEventReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
StaxParserUtil.getNextEvent(xmlEventReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException(ErrorCodes.FAILED_PARSING + "SAML Parsing has failed");
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,12 +18,9 @@
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
|
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
|
||||||
import org.keycloak.adapters.saml.config.SP;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLEventReader;
|
import javax.xml.stream.XMLEventReader;
|
||||||
import javax.xml.stream.events.StartElement;
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
@ -31,28 +28,33 @@ import javax.xml.stream.events.StartElement;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class KeycloakSamlAdapterXMLParser extends AbstractParser {
|
public class KeycloakSamlAdapterV1Parser extends AbstractKeycloakSamlAdapterV1Parser<KeycloakSamlAdapter> {
|
||||||
|
|
||||||
@Override
|
private static final KeycloakSamlAdapterV1Parser INSTANCE = new KeycloakSamlAdapterV1Parser();
|
||||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
KeycloakSamlAdapter adapter = new KeycloakSamlAdapter();
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYCLOAK_SAML_ADAPTER);
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.SP_ELEMENT)) {
|
|
||||||
SPXmlParser parser = new SPXmlParser();
|
|
||||||
SP sp = (SP)parser.parse(xmlEventReader);
|
|
||||||
if (sp != null) adapter.getSps().add(sp);
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
private KeycloakSamlAdapterV1Parser() {
|
||||||
return adapter;
|
super(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static KeycloakSamlAdapterV1Parser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeycloakSamlAdapter instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
return new KeycloakSamlAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, KeycloakSamlAdapter target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case SP:
|
||||||
|
target.addSp(SpParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Ignore unknown tags
|
||||||
|
StaxParserUtil.bypassElementBlock(xmlEventReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.saml.processing.core.parsers.util.HasQName;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author hmlnarik
|
||||||
|
*/
|
||||||
|
public enum KeycloakSamlAdapterV1QNames implements HasQName {
|
||||||
|
|
||||||
|
ATTRIBUTE("Attribute"),
|
||||||
|
CERTIFICATE("Certificate"),
|
||||||
|
CERTIFICATE_PEM("CertificatePem"),
|
||||||
|
HTTP_CLIENT("HttpClient"),
|
||||||
|
IDP("IDP"),
|
||||||
|
KEY("Key"),
|
||||||
|
KEYCLOAK_SAML_ADAPTER("keycloak-saml-adapter"),
|
||||||
|
KEYS("Keys"),
|
||||||
|
KEY_STORE("KeyStore"),
|
||||||
|
PRINCIPAL_NAME_MAPPING("PrincipalNameMapping"),
|
||||||
|
PRIVATE_KEY("PrivateKey"),
|
||||||
|
PRIVATE_KEY_PEM("PrivateKeyPem"),
|
||||||
|
PUBLIC_KEY_PEM("PublicKeyPem"),
|
||||||
|
ROLE_IDENTIFIERS("RoleIdentifiers"),
|
||||||
|
SINGLE_LOGOUT_SERVICE("SingleLogoutService"),
|
||||||
|
SINGLE_SIGN_ON_SERVICE("SingleSignOnService"),
|
||||||
|
SP("SP"),
|
||||||
|
|
||||||
|
ATTR_ALIAS(null, "alias"),
|
||||||
|
ATTR_ALLOW_ANY_HOSTNAME(null, "allowAnyHostname"),
|
||||||
|
ATTR_ASSERTION_CONSUMER_SERVICE_URL(null, "assertionConsumerServiceUrl"),
|
||||||
|
ATTR_ATTRIBUTE(null, "attribute"),
|
||||||
|
ATTR_AUTODETECT_BEARER_ONLY(null, "autodetectBearerOnly"),
|
||||||
|
ATTR_BINDING_URL(null, "bindingUrl"),
|
||||||
|
ATTR_CLIENT_KEYSTORE(null, "clientKeystore"),
|
||||||
|
ATTR_CLIENT_KEYSTORE_PASSWORD(null, "clientKeystorePassword"),
|
||||||
|
ATTR_CONNECTION_POOL_SIZE(null, "connectionPoolSize"),
|
||||||
|
ATTR_DISABLE_TRUST_MANAGER(null, "disableTrustManager"),
|
||||||
|
ATTR_ENCRYPTION(null, "encryption"),
|
||||||
|
ATTR_ENTITY_ID(null, "entityID"),
|
||||||
|
ATTR_FILE(null, "file"),
|
||||||
|
ATTR_FORCE_AUTHENTICATION(null, "forceAuthentication"),
|
||||||
|
ATTR_IS_PASSIVE(null, "isPassive"),
|
||||||
|
ATTR_LOGOUT_PAGE(null, "logoutPage"),
|
||||||
|
ATTR_NAME(null, "name"),
|
||||||
|
ATTR_NAME_ID_POLICY_FORMAT(null, "nameIDPolicyFormat"),
|
||||||
|
ATTR_PASSWORD(null, "password"),
|
||||||
|
ATTR_POLICY(null, "policy"),
|
||||||
|
ATTR_POST_BINDING_URL(null, "postBindingUrl"),
|
||||||
|
ATTR_PROXY_URL(null, "proxyUrl"),
|
||||||
|
ATTR_REDIRECT_BINDING_URL(null, "redirectBindingUrl"),
|
||||||
|
ATTR_REQUEST_BINDING(null, "requestBinding"),
|
||||||
|
ATTR_RESOURCE(null, "resource"),
|
||||||
|
ATTR_RESPONSE_BINDING(null, "responseBinding"),
|
||||||
|
ATTR_SIGNATURES_REQUIRED(null, "signaturesRequired"),
|
||||||
|
ATTR_SIGNATURE_ALGORITHM(null, "signatureAlgorithm"),
|
||||||
|
ATTR_SIGNATURE_CANONICALIZATION_METHOD(null, "signatureCanonicalizationMethod"),
|
||||||
|
ATTR_SIGNING(null, "signing"),
|
||||||
|
ATTR_SIGN_REQUEST(null, "signRequest"),
|
||||||
|
ATTR_SIGN_RESPONSE(null, "signResponse"),
|
||||||
|
ATTR_SSL_POLICY(null, "sslPolicy"),
|
||||||
|
ATTR_TRUSTSTORE(null, "truststore"),
|
||||||
|
ATTR_TRUSTSTORE_PASSWORD(null, "truststorePassword"),
|
||||||
|
ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN(null, "turnOffChangeSessionIdOnLogin"),
|
||||||
|
ATTR_TYPE(null, "type"),
|
||||||
|
ATTR_VALIDATE_ASSERTION_SIGNATURE(null, "validateAssertionSignature"),
|
||||||
|
ATTR_VALIDATE_REQUEST_SIGNATURE(null, "validateRequestSignature"),
|
||||||
|
ATTR_VALIDATE_RESPONSE_SIGNATURE(null, "validateResponseSignature"),
|
||||||
|
|
||||||
|
UNKNOWN_ELEMENT("")
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final String NS_URI = "urn:keycloak:saml:adapter";
|
||||||
|
|
||||||
|
private final QName qName;
|
||||||
|
|
||||||
|
private KeycloakSamlAdapterV1QNames(String localName) {
|
||||||
|
this(NS_URI, localName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeycloakSamlAdapterV1QNames(HasQName source) {
|
||||||
|
this.qName = source.getQName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeycloakSamlAdapterV1QNames(String nsUri, String localName) {
|
||||||
|
this.qName = new QName(nsUri == null ? null : nsUri, localName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QName getQName() {
|
||||||
|
return qName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QName getQName(String prefix) {
|
||||||
|
return new QName(this.qName.getNamespaceURI(), this.qName.getLocalPart(), prefix);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.Key;
|
||||||
|
import org.keycloak.adapters.saml.config.SP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class KeysParser extends AbstractKeycloakSamlAdapterV1Parser<List<Key>> {
|
||||||
|
|
||||||
|
private static final KeysParser INSTANCE = new KeysParser();
|
||||||
|
|
||||||
|
private KeysParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.KEYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeysParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Key> instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, List<Key> target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case KEY:
|
||||||
|
target.add(KeyParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
|
||||||
|
|
||||||
import org.keycloak.adapters.saml.config.Key;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
|
||||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLEventReader;
|
|
||||||
import javax.xml.stream.events.EndElement;
|
|
||||||
import javax.xml.stream.events.StartElement;
|
|
||||||
import javax.xml.stream.events.XMLEvent;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class KeysXmlParser extends AbstractParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_ELEMENT);
|
|
||||||
List<Key> keys = new LinkedList<>();
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.KEYS_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
throw logger.parserUnknownEndElement(endElementName, xmlEvent.getLocation());
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.KEY_ELEMENT)) {
|
|
||||||
KeyXmlParser parser = new KeyXmlParser();
|
|
||||||
Key key = (Key)parser.parse(xmlEventReader);
|
|
||||||
keys.add(key);
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.SP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class PrincipalNameMappingParser extends AbstractKeycloakSamlAdapterV1Parser<SP.PrincipalNameMapping> {
|
||||||
|
|
||||||
|
private static final PrincipalNameMappingParser INSTANCE = new PrincipalNameMappingParser();
|
||||||
|
|
||||||
|
private PrincipalNameMappingParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.PRINCIPAL_NAME_MAPPING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrincipalNameMappingParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SP.PrincipalNameMapping instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
|
||||||
|
|
||||||
|
mapping.setPolicy(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POLICY));
|
||||||
|
mapping.setAttributeName(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ATTRIBUTE));
|
||||||
|
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, SP.PrincipalNameMapping target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class RoleMappingParser extends AbstractKeycloakSamlAdapterV1Parser<Set<String>> {
|
||||||
|
|
||||||
|
private static final RoleMappingParser INSTANCE = new RoleMappingParser();
|
||||||
|
|
||||||
|
private RoleMappingParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.ROLE_IDENTIFIERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RoleMappingParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, Set<String> target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case ATTRIBUTE:
|
||||||
|
target.add(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_NAME));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,177 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.adapters.saml.config.parsers;
|
|
||||||
|
|
||||||
import org.keycloak.adapters.saml.config.IDP;
|
|
||||||
import org.keycloak.adapters.saml.config.Key;
|
|
||||||
import org.keycloak.adapters.saml.config.SP;
|
|
||||||
import org.keycloak.common.util.StringPropertyReplacer;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
|
||||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLEventReader;
|
|
||||||
import javax.xml.stream.events.EndElement;
|
|
||||||
import javax.xml.stream.events.StartElement;
|
|
||||||
import javax.xml.stream.events.XMLEvent;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
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 int getIntegerAttributeValue(StartElement startElement, String tag, int defaultValue) {
|
|
||||||
String result = getAttributeValue(startElement, tag);
|
|
||||||
if (result == null)
|
|
||||||
return defaultValue;
|
|
||||||
return Integer.valueOf(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
|
||||||
if (entityID == null) {
|
|
||||||
throw new ParsingException("entityID must be set on SP");
|
|
||||||
|
|
||||||
}
|
|
||||||
sp.setEntityID(entityID);
|
|
||||||
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));
|
|
||||||
sp.setIsPassive(getBooleanAttributeValue(startElement, ConfigXmlConstants.IS_PASSIVE_ATTR));
|
|
||||||
sp.setAutodetectBearerOnly(getBooleanAttributeValue(startElement, ConfigXmlConstants.AUTODETECT_BEARER_ONLY_ATTR));
|
|
||||||
sp.setTurnOffChangeSessionIdOnLogin(getBooleanAttributeValue(startElement, ConfigXmlConstants.TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR));
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.SP_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
|
|
||||||
KeysXmlParser parser = new KeysXmlParser();
|
|
||||||
List<Key> keys = (List<Key>) parser.parse(xmlEventReader);
|
|
||||||
sp.setKeys(keys);
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.PRINCIPAL_NAME_MAPPING_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
String policy = getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
|
|
||||||
if (policy == null) {
|
|
||||||
throw new ParsingException("PrincipalNameMapping element must have the policy attribute set");
|
|
||||||
|
|
||||||
}
|
|
||||||
String attribute = getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
|
|
||||||
SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
|
|
||||||
mapping.setPolicy(policy);
|
|
||||||
mapping.setAttributeName(attribute);
|
|
||||||
sp.setPrincipalNameMapping(mapping);
|
|
||||||
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT)) {
|
|
||||||
parseRoleMapping(xmlEventReader, sp);
|
|
||||||
} else if (tag.equals(ConfigXmlConstants.IDP_ELEMENT)) {
|
|
||||||
IDPXmlParser parser = new IDPXmlParser();
|
|
||||||
IDP idp = (IDP) parser.parse(xmlEventReader);
|
|
||||||
sp.setIdp(idp);
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void parseRoleMapping(XMLEventReader xmlEventReader, SP sp) throws ParsingException {
|
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT);
|
|
||||||
Set<String> roleAttributes = new HashSet<>();
|
|
||||||
while (xmlEventReader.hasNext()) {
|
|
||||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
|
||||||
if (xmlEvent == null)
|
|
||||||
break;
|
|
||||||
if (xmlEvent instanceof EndElement) {
|
|
||||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
|
||||||
String endElementName = StaxParserUtil.getElementName(endElement);
|
|
||||||
if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
|
||||||
if (startElement == null)
|
|
||||||
break;
|
|
||||||
String tag = StaxParserUtil.getElementName(startElement);
|
|
||||||
if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
|
|
||||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
|
||||||
String attributeValue = getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
|
|
||||||
if (attributeValue == null) {
|
|
||||||
throw new ParsingException("RoleMapping Attribute element must have the name attribute set");
|
|
||||||
|
|
||||||
}
|
|
||||||
roleAttributes.add(attributeValue);
|
|
||||||
} else {
|
|
||||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
sp.setRoleAttributes(roleAttributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.IDP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SingleLogoutServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleLogoutService> {
|
||||||
|
|
||||||
|
private static final SingleLogoutServiceParser INSTANCE = new SingleLogoutServiceParser();
|
||||||
|
|
||||||
|
private SingleLogoutServiceParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.SINGLE_LOGOUT_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SingleLogoutServiceParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IDP.SingleLogoutService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
|
||||||
|
|
||||||
|
slo.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
|
||||||
|
slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
|
||||||
|
slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_REQUEST_SIGNATURE));
|
||||||
|
slo.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
|
||||||
|
slo.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
|
||||||
|
slo.setSignResponse(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_RESPONSE));
|
||||||
|
slo.setPostBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POST_BINDING_URL));
|
||||||
|
slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REDIRECT_BINDING_URL));
|
||||||
|
|
||||||
|
return slo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleLogoutService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.IDP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SingleSignOnServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleSignOnService> {
|
||||||
|
|
||||||
|
private static final SingleSignOnServiceParser INSTANCE = new SingleSignOnServiceParser();
|
||||||
|
|
||||||
|
private SingleSignOnServiceParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.SINGLE_SIGN_ON_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SingleSignOnServiceParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IDP.SingleSignOnService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
|
||||||
|
|
||||||
|
sso.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
|
||||||
|
sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
|
||||||
|
sso.setValidateAssertionSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_ASSERTION_SIGNATURE));
|
||||||
|
sso.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
|
||||||
|
sso.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
|
||||||
|
sso.setBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_BINDING_URL));
|
||||||
|
sso.setAssertionConsumerServiceUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ASSERTION_CONSUMER_SERVICE_URL));
|
||||||
|
|
||||||
|
return sso;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleSignOnService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.adapters.saml.config.parsers;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.saml.config.SP;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
|
import javax.xml.stream.events.StartElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SpParser extends AbstractKeycloakSamlAdapterV1Parser<SP> {
|
||||||
|
|
||||||
|
private static final SpParser INSTANCE = new SpParser();
|
||||||
|
|
||||||
|
private SpParser() {
|
||||||
|
super(KeycloakSamlAdapterV1QNames.SP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpParser getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||||
|
final SP sp = new SP();
|
||||||
|
|
||||||
|
sp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
|
||||||
|
|
||||||
|
sp.setSslPolicy(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SSL_POLICY));
|
||||||
|
sp.setLogoutPage(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_LOGOUT_PAGE));
|
||||||
|
sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_NAME_ID_POLICY_FORMAT));
|
||||||
|
sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FORCE_AUTHENTICATION));
|
||||||
|
sp.setIsPassive(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_IS_PASSIVE));
|
||||||
|
sp.setAutodetectBearerOnly(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_AUTODETECT_BEARER_ONLY));
|
||||||
|
sp.setTurnOffChangeSessionIdOnLogin(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN));
|
||||||
|
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processSubElement(XMLEventReader xmlEventReader, SP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||||
|
switch (element) {
|
||||||
|
case KEYS:
|
||||||
|
target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINCIPAL_NAME_MAPPING:
|
||||||
|
target.setPrincipalNameMapping(PrincipalNameMappingParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROLE_IDENTIFIERS:
|
||||||
|
target.setRoleAttributes(RoleMappingParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDP:
|
||||||
|
target.setIdp(IdpParser.getInstance().parse(xmlEventReader));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
import org.keycloak.saml.common.util.DocumentUtil;
|
import org.keycloak.saml.common.util.DocumentUtil;
|
||||||
|
import org.keycloak.saml.processing.core.parsers.saml.xmldsig.XmlDSigQNames;
|
||||||
import org.keycloak.saml.processing.core.util.NamespaceContext;
|
import org.keycloak.saml.processing.core.util.NamespaceContext;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
@ -88,7 +89,7 @@ public class SamlDescriptorIDPKeysExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyInfo processKeyDescriptor(Element keyDescriptor) throws MarshalException {
|
private KeyInfo processKeyDescriptor(Element keyDescriptor) throws MarshalException {
|
||||||
NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), JBossSAMLConstants.KEY_INFO.get());
|
NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), XmlDSigQNames.KEY_INFO.getQName().getLocalPart());
|
||||||
|
|
||||||
if (childNodes.getLength() == 0) {
|
if (childNodes.getLength() == 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -14,7 +14,7 @@ import javax.xml.crypto.dsig.keyinfo.X509Data;
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import org.keycloak.adapters.saml.config.parsers.ConfigXmlConstants;
|
import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterV1QNames;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
@ -41,15 +41,15 @@ public class HttpAdapterUtilsTest {
|
||||||
|
|
||||||
assertThat(res, notNullValue());
|
assertThat(res, notNullValue());
|
||||||
assertThat(res.keySet(), hasItems(KeyTypes.SIGNING.value()));
|
assertThat(res.keySet(), hasItems(KeyTypes.SIGNING.value()));
|
||||||
assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR), notNullValue());
|
assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()), notNullValue());
|
||||||
assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR).size(), equalTo(2));
|
assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).size(), equalTo(2));
|
||||||
|
|
||||||
KeyInfo ki;
|
KeyInfo ki;
|
||||||
KeyName keyName;
|
KeyName keyName;
|
||||||
X509Data x509data;
|
X509Data x509data;
|
||||||
X509Certificate x509certificate;
|
X509Certificate x509certificate;
|
||||||
|
|
||||||
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(0);
|
ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).get(0);
|
||||||
assertThat(ki.getContent().size(), equalTo(2));
|
assertThat(ki.getContent().size(), equalTo(2));
|
||||||
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
|
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
|
||||||
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
|
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
|
||||||
|
@ -63,7 +63,7 @@ public class HttpAdapterUtilsTest {
|
||||||
assertThat(x509certificate, notNullValue());
|
assertThat(x509certificate, notNullValue());
|
||||||
assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
|
assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
|
||||||
|
|
||||||
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(1);
|
ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).get(1);
|
||||||
assertThat(ki.getContent().size(), equalTo(2));
|
assertThat(ki.getContent().size(), equalTo(2));
|
||||||
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
|
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
|
||||||
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
|
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
|
||||||
|
|
|
@ -30,6 +30,8 @@ import java.io.InputStream;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -67,7 +69,7 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidationKeyInvalid() throws Exception {
|
public void testValidationKeyInvalid() throws Exception {
|
||||||
InputStream schemaIs = KeycloakSamlAdapterXMLParser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
|
InputStream schemaIs = KeycloakSamlAdapterV1Parser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
|
||||||
InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
|
InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
|
||||||
assertNotNull(is);
|
assertNotNull(is);
|
||||||
assertNotNull(schemaIs);
|
assertNotNull(schemaIs);
|
||||||
|
@ -77,12 +79,14 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testXmlParser() throws Exception {
|
public void testParseSimpleFileNoNamespace() throws Exception {
|
||||||
InputStream is = getClass().getResourceAsStream("keycloak-saml.xml");
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-no-namespace.xml", KeycloakSamlAdapter.class);
|
||||||
assertNotNull(is);
|
}
|
||||||
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
|
|
||||||
|
@Test
|
||||||
|
public void testXmlParserBaseFile() throws Exception {
|
||||||
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml.xml", KeycloakSamlAdapter.class);
|
||||||
|
|
||||||
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
|
|
||||||
assertNotNull(config);
|
assertNotNull(config);
|
||||||
assertEquals(1, config.getSps().size());
|
assertEquals(1, config.getSps().size());
|
||||||
SP sp = config.getSps().get(0);
|
SP sp = config.getSps().get(0);
|
||||||
|
@ -121,7 +125,7 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
assertEquals("POST", idp.getSingleSignOnService().getRequestBinding());
|
assertEquals("POST", idp.getSingleSignOnService().getRequestBinding());
|
||||||
assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
|
assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
|
||||||
|
|
||||||
assertTrue(idp.getSingleLogoutService().isSignRequest());
|
assertFalse(idp.getSingleLogoutService().isSignRequest());
|
||||||
assertTrue(idp.getSingleLogoutService().isSignResponse());
|
assertTrue(idp.getSingleLogoutService().isSignResponse());
|
||||||
assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
|
assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
|
||||||
assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
|
assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
|
||||||
|
@ -135,14 +139,17 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
|
assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> T parseKeycloakSamlAdapterConfig(String fileName, Class<T> targetClass) throws ParsingException, IOException {
|
||||||
|
try (InputStream is = getClass().getResourceAsStream(fileName)) {
|
||||||
|
KeycloakSamlAdapterParser parser = KeycloakSamlAdapterParser.getInstance();
|
||||||
|
return targetClass.cast(parser.parse(is));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testXmlParserMultipleSigningKeys() throws Exception {
|
public void testXmlParserMultipleSigningKeys() throws Exception {
|
||||||
InputStream is = getClass().getResourceAsStream("keycloak-saml-multiple-signing-keys.xml");
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-multiple-signing-keys.xml", KeycloakSamlAdapter.class);
|
||||||
assertNotNull(is);
|
|
||||||
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
|
|
||||||
|
|
||||||
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
|
|
||||||
assertNotNull(config);
|
assertNotNull(config);
|
||||||
assertEquals(1, config.getSps().size());
|
assertEquals(1, config.getSps().size());
|
||||||
SP sp = config.getSps().get(0);
|
SP sp = config.getSps().get(0);
|
||||||
|
@ -158,11 +165,7 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testXmlParserHttpClientSettings() throws Exception {
|
public void testXmlParserHttpClientSettings() throws Exception {
|
||||||
InputStream is = getClass().getResourceAsStream("keycloak-saml-wth-http-client-settings.xml");
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-wth-http-client-settings.xml", KeycloakSamlAdapter.class);
|
||||||
assertNotNull(is);
|
|
||||||
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
|
|
||||||
|
|
||||||
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
|
|
||||||
assertNotNull(config);
|
assertNotNull(config);
|
||||||
assertEquals(1, config.getSps().size());
|
assertEquals(1, config.getSps().size());
|
||||||
SP sp = config.getSps().get(0);
|
SP sp = config.getSps().get(0);
|
||||||
|
@ -178,4 +181,66 @@ public class KeycloakSamlAdapterXMLParserTest {
|
||||||
assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
|
assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
|
||||||
assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
|
assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testXmlParserSystemPropertiesNoPropertiesSet() throws Exception {
|
||||||
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
|
||||||
|
assertNotNull(config);
|
||||||
|
assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
|
||||||
|
SP sp = config.getSps().get(0);
|
||||||
|
IDP idp = sp.getIdp();
|
||||||
|
|
||||||
|
assertThat(sp.getEntityID(), is("sp"));
|
||||||
|
assertThat(sp.getSslPolicy(), is("${keycloak-saml-properties.sslPolicy}"));
|
||||||
|
|
||||||
|
assertThat(idp.isSignaturesRequired(), is(false));
|
||||||
|
|
||||||
|
assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
|
||||||
|
assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
|
||||||
|
|
||||||
|
assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
|
||||||
|
assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
|
||||||
|
|
||||||
|
// These should take default from IDP.signaturesRequired
|
||||||
|
assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(false));
|
||||||
|
assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(false));
|
||||||
|
|
||||||
|
assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testXmlParserSystemPropertiesWithPropertiesSet() throws Exception {
|
||||||
|
try {
|
||||||
|
System.setProperty("keycloak-saml-properties.entityID", "meid");
|
||||||
|
System.setProperty("keycloak-saml-properties.sslPolicy", "INTERNAL");
|
||||||
|
System.setProperty("keycloak-saml-properties.signaturesRequired", "true");
|
||||||
|
|
||||||
|
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
|
||||||
|
assertNotNull(config);
|
||||||
|
assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
|
||||||
|
SP sp = config.getSps().get(0);
|
||||||
|
IDP idp = sp.getIdp();
|
||||||
|
|
||||||
|
assertThat(sp.getEntityID(), is("meid"));
|
||||||
|
assertThat(sp.getSslPolicy(), is("INTERNAL"));
|
||||||
|
assertThat(idp.isSignaturesRequired(), is(true));
|
||||||
|
|
||||||
|
assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
|
||||||
|
assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
|
||||||
|
|
||||||
|
assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
|
||||||
|
assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
|
||||||
|
|
||||||
|
// These should take default from IDP.signaturesRequired
|
||||||
|
assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(true));
|
||||||
|
assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(true));
|
||||||
|
|
||||||
|
// This is false by default
|
||||||
|
assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
|
||||||
|
} finally {
|
||||||
|
System.clearProperty("keycloak-saml-properties.entityID");
|
||||||
|
System.clearProperty("keycloak-saml-properties.sslPolicy");
|
||||||
|
System.clearProperty("keycloak-saml-properties.signaturesRequired");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<!--
|
||||||
|
~ 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="${keycloak-saml-properties.entityID:sp}"
|
||||||
|
sslPolicy="EXTERNAL"
|
||||||
|
nameIDPolicyFormat="format"
|
||||||
|
forceAuthentication="true"
|
||||||
|
isPassive="true">
|
||||||
|
<Keys>
|
||||||
|
<Key signing="true">
|
||||||
|
<KeyStore file="file" resource="cp" password="pw">
|
||||||
|
<PrivateKey alias="private alias" password="private pw"/>
|
||||||
|
<Certificate alias="cert alias"/>
|
||||||
|
</KeyStore>
|
||||||
|
</Key>
|
||||||
|
<Key encryption="true">
|
||||||
|
<PrivateKeyPem>
|
||||||
|
private pem
|
||||||
|
</PrivateKeyPem>
|
||||||
|
<PublicKeyPem>
|
||||||
|
public pem
|
||||||
|
</PublicKeyPem>
|
||||||
|
</Key>
|
||||||
|
</Keys>
|
||||||
|
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
|
||||||
|
<RoleIdentifiers>
|
||||||
|
<Attribute name="member"/>
|
||||||
|
</RoleIdentifiers>
|
||||||
|
<IDP entityID="idp"
|
||||||
|
signatureAlgorithm="RSA_SHA256"
|
||||||
|
signatureCanonicalizationMethod="canon"
|
||||||
|
signaturesRequired="true"
|
||||||
|
>
|
||||||
|
<SingleSignOnService signRequest="true"
|
||||||
|
validateResponseSignature="true"
|
||||||
|
requestBinding="POST"
|
||||||
|
bindingUrl="url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SingleLogoutService
|
||||||
|
validateRequestSignature="true"
|
||||||
|
validateResponseSignature="true"
|
||||||
|
signRequest="true"
|
||||||
|
signResponse="true"
|
||||||
|
requestBinding="REDIRECT"
|
||||||
|
responseBinding="POST"
|
||||||
|
postBindingUrl="posturl"
|
||||||
|
redirectBindingUrl="redirecturl"
|
||||||
|
/>
|
||||||
|
<Keys>
|
||||||
|
<Key signing="true">
|
||||||
|
<CertificatePem>
|
||||||
|
cert pem
|
||||||
|
</CertificatePem>
|
||||||
|
</Key>
|
||||||
|
</Keys>
|
||||||
|
</IDP>
|
||||||
|
</SP>
|
||||||
|
</keycloak-saml-adapter>
|
|
@ -0,0 +1,74 @@
|
||||||
|
<!--
|
||||||
|
~ 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 xmlns="urn:keycloak:saml:adapter"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_9.xsd">
|
||||||
|
<SP entityID="${keycloak-saml-properties.entityID:sp}"
|
||||||
|
sslPolicy="${keycloak-saml-properties.sslPolicy}"
|
||||||
|
nameIDPolicyFormat="format"
|
||||||
|
forceAuthentication="true"
|
||||||
|
isPassive="true">
|
||||||
|
<Keys>
|
||||||
|
<Key signing="true">
|
||||||
|
<KeyStore file="file" resource="cp" password="pw">
|
||||||
|
<PrivateKey alias="private alias" password="private pw"/>
|
||||||
|
<Certificate alias="cert alias"/>
|
||||||
|
</KeyStore>
|
||||||
|
</Key>
|
||||||
|
<Key encryption="true">
|
||||||
|
<PrivateKeyPem>
|
||||||
|
private pem
|
||||||
|
</PrivateKeyPem>
|
||||||
|
<PublicKeyPem>
|
||||||
|
public pem
|
||||||
|
</PublicKeyPem>
|
||||||
|
</Key>
|
||||||
|
</Keys>
|
||||||
|
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
|
||||||
|
<RoleIdentifiers>
|
||||||
|
<Attribute name="member"/>
|
||||||
|
</RoleIdentifiers>
|
||||||
|
<IDP entityID="idp"
|
||||||
|
signatureAlgorithm="RSA_SHA256"
|
||||||
|
signatureCanonicalizationMethod="canon"
|
||||||
|
signaturesRequired="${keycloak-saml-properties.signaturesRequired:false}"
|
||||||
|
>
|
||||||
|
<SingleSignOnService signRequest="true"
|
||||||
|
validateResponseSignature="true"
|
||||||
|
requestBinding="POST"
|
||||||
|
bindingUrl="url"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SingleLogoutService
|
||||||
|
signRequest="true"
|
||||||
|
signResponse="false"
|
||||||
|
requestBinding="REDIRECT"
|
||||||
|
responseBinding="POST"
|
||||||
|
postBindingUrl="posturl"
|
||||||
|
redirectBindingUrl="redirecturl"
|
||||||
|
/>
|
||||||
|
<Keys>
|
||||||
|
<Key signing="true">
|
||||||
|
<CertificatePem>
|
||||||
|
cert pem
|
||||||
|
</CertificatePem>
|
||||||
|
</Key>
|
||||||
|
</Keys>
|
||||||
|
</IDP>
|
||||||
|
</SP>
|
||||||
|
</keycloak-saml-adapter>
|
|
@ -57,7 +57,7 @@
|
||||||
<SingleLogoutService
|
<SingleLogoutService
|
||||||
validateRequestSignature="true"
|
validateRequestSignature="true"
|
||||||
validateResponseSignature="true"
|
validateResponseSignature="true"
|
||||||
signRequest="true"
|
signRequest="false"
|
||||||
signResponse="true"
|
signResponse="true"
|
||||||
requestBinding="REDIRECT"
|
requestBinding="REDIRECT"
|
||||||
responseBinding="POST"
|
responseBinding="POST"
|
||||||
|
|
|
@ -37,7 +37,7 @@ import javax.xml.stream.events.XMLEvent;
|
||||||
public abstract class AbstractStaxParser<T, E> implements StaxParser {
|
public abstract class AbstractStaxParser<T, E> implements StaxParser {
|
||||||
|
|
||||||
protected static final PicketLinkLogger LOGGER = PicketLinkLoggerFactory.getLogger();
|
protected static final PicketLinkLogger LOGGER = PicketLinkLoggerFactory.getLogger();
|
||||||
private final QName expectedStartElement;
|
protected final QName expectedStartElement;
|
||||||
private final E unknownElement;
|
private final E unknownElement;
|
||||||
|
|
||||||
public AbstractStaxParser(QName expectedStartElement, E unknownElement) {
|
public AbstractStaxParser(QName expectedStartElement, E unknownElement) {
|
||||||
|
@ -51,7 +51,8 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
|
||||||
|
|
||||||
// Get the start element and validate it is the expected one
|
// Get the start element and validate it is the expected one
|
||||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||||
StaxParserUtil.validate(startElement, expectedStartElement);
|
final QName actualQName = startElement.getName();
|
||||||
|
validateStartElement(startElement);
|
||||||
T target = instantiateElement(xmlEventReader, startElement);
|
T target = instantiateElement(xmlEventReader, startElement);
|
||||||
|
|
||||||
// STATE: Start element has been read.
|
// STATE: Start element has been read.
|
||||||
|
@ -76,7 +77,7 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If end element corresponding to this start element, stop processing.
|
// If end element corresponding to this start element, stop processing.
|
||||||
if (Objects.equals(qName, expectedStartElement)) {
|
if (Objects.equals(qName, actualQName)) {
|
||||||
// consume the end element and finish parsing of this tag
|
// consume the end element and finish parsing of this tag
|
||||||
StaxParserUtil.advance(xmlEventReader);
|
StaxParserUtil.advance(xmlEventReader);
|
||||||
break;
|
break;
|
||||||
|
@ -105,13 +106,21 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
|
||||||
|
|
||||||
// In case of recursive nesting the same element, the corresponding end element MUST be handled
|
// In case of recursive nesting the same element, the corresponding end element MUST be handled
|
||||||
// in the {@code processSubElement} method and MUST NOT be consumed here.
|
// in the {@code processSubElement} method and MUST NOT be consumed here.
|
||||||
if (Objects.equals(expectedStartElement, currentSubelement) || isUnknownElement(token)) {
|
if (Objects.equals(actualQName, currentSubelement) || isUnknownElement(token)) {
|
||||||
currentSubelement = null;
|
currentSubelement = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the given startElement has the expected properties (namely {@link QName} matches the expected one).
|
||||||
|
* @param startElement
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected void validateStartElement(StartElement startElement) {
|
||||||
|
StaxParserUtil.validate(startElement, expectedStartElement);
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isUnknownElement(E token) {
|
protected boolean isUnknownElement(E token) {
|
||||||
return token == null || Objects.equals(token, unknownElement);
|
return token == null || Objects.equals(token, unknownElement);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.common.util;
|
package org.keycloak.saml.common.util;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.StringPropertyReplacer;
|
||||||
import org.keycloak.saml.common.ErrorCodes;
|
import org.keycloak.saml.common.ErrorCodes;
|
||||||
import org.keycloak.saml.common.PicketLinkLogger;
|
import org.keycloak.saml.common.PicketLinkLogger;
|
||||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||||
|
@ -189,6 +190,23 @@ public class StaxParserUtil {
|
||||||
return value == null ? null : trim(value);
|
return value == null ? null : trim(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an {@code Attribute}, get its trimmed value, replacing every occurrence of ${..} by corresponding system property value
|
||||||
|
*
|
||||||
|
* @param attribute
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getAttributeValueRP(Attribute attribute) {
|
||||||
|
if (attribute == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String value = attribute.getValue();
|
||||||
|
|
||||||
|
return value == null ? null : trim(StringPropertyReplacer.replaceProperties(value));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Attribute value
|
* Get the Attribute value
|
||||||
*
|
*
|
||||||
|
@ -214,6 +232,21 @@ public class StaxParserUtil {
|
||||||
return getAttributeValue(startElement, attrName.getQName());
|
return getAttributeValue(startElement, attrName.getQName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
|
||||||
|
*
|
||||||
|
* @param startElement
|
||||||
|
* @param tag localpart of the qname of the attribute
|
||||||
|
*
|
||||||
|
* @see StringPropertyReplacer#replaceProperties(java.lang.String)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getAttributeValueRP(StartElement startElement, HasQName attrName) {
|
||||||
|
final String value = getAttributeValue(startElement, attrName.getQName());
|
||||||
|
return value == null ? null : StringPropertyReplacer.replaceProperties(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Attribute value
|
* Get the Attribute value
|
||||||
*
|
*
|
||||||
|
@ -269,6 +302,20 @@ public class StaxParserUtil {
|
||||||
return value == null ? null : Integer.valueOf(value);
|
return value == null ? null : Integer.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
|
||||||
|
*
|
||||||
|
* @param startElement
|
||||||
|
* @param tag localpart of the qname of the attribute
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Integer getIntegerAttributeValueRP(StartElement startElement, HasQName attrName) {
|
||||||
|
Attribute attr = startElement.getAttributeByName(attrName.getQName());
|
||||||
|
String value = getAttributeValueRP(attr);
|
||||||
|
return value == null ? null : Integer.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Attribute value
|
* Get the Attribute value
|
||||||
*
|
*
|
||||||
|
@ -283,6 +330,20 @@ public class StaxParserUtil {
|
||||||
return value == null ? null : Boolean.valueOf(value);
|
return value == null ? null : Boolean.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
|
||||||
|
*
|
||||||
|
* @param startElement
|
||||||
|
* @param tag localpart of the qname of the attribute
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Boolean getBooleanAttributeValueRP(StartElement startElement, HasQName attrName) {
|
||||||
|
Attribute attr = startElement.getAttributeByName(attrName.getQName());
|
||||||
|
String value = getAttributeValueRP(attr);
|
||||||
|
return value == null ? null : Boolean.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Attribute value
|
* Get the Attribute value
|
||||||
*
|
*
|
||||||
|
@ -322,6 +383,14 @@ public class StaxParserUtil {
|
||||||
return StaxParserUtil.getAttributeValue(attr);
|
return StaxParserUtil.getAttributeValue(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRequiredAttributeValueRP(StartElement startElement, HasQName attrName) throws ParsingException {
|
||||||
|
final QName qName = attrName.getQName();
|
||||||
|
Attribute attr = startElement.getAttributeByName(qName);
|
||||||
|
if (attr == null)
|
||||||
|
throw logger.parserRequiredAttribute(qName.getLocalPart());
|
||||||
|
return StaxParserUtil.getAttributeValueRP(attr);
|
||||||
|
}
|
||||||
|
|
||||||
private static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
|
private static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -53,6 +53,11 @@ public class QNameEnumLookup<E extends Enum<E> & HasQName> {
|
||||||
this.qNameConstants = Collections.unmodifiableMap(q);
|
this.qNameConstants = Collections.unmodifiableMap(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up the given {@code name} and returns the corresponding constant.
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public E from(QName name) {
|
public E from(QName name) {
|
||||||
E c = qNameConstants.get(name);
|
E c = qNameConstants.get(name);
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
|
|
|
@ -1204,7 +1204,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
|
||||||
Client client = ClientBuilder.newClient();
|
Client client = ClientBuilder.newClient();
|
||||||
|
|
||||||
// Do not redirect client to login page if it's an XHR
|
// Do not redirect client to login page if it's an XHR
|
||||||
WebTarget target = client.target(salesPostAutodetectServletPage.toString());
|
WebTarget target = client.target(salesPostAutodetectServletPage.toString() + "/");
|
||||||
Response response = target.request().header("X-Requested-With", "XMLHttpRequest").get();
|
Response response = target.request().header("X-Requested-With", "XMLHttpRequest").get();
|
||||||
Assert.assertEquals(401, response.getStatus());
|
Assert.assertEquals(401, response.getStatus());
|
||||||
response.close();
|
response.close();
|
||||||
|
|
Loading…
Reference in a new issue