saml undertow sp
This commit is contained in:
parent
861a13501a
commit
cc9d6d0cf7
34 changed files with 3157 additions and 70 deletions
5
pom.xml
5
pom.xml
|
@ -990,6 +990,11 @@
|
|||
<artifactId>keycloak-saml-adapter-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-saml-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-saml-adapter-core</artifactId>
|
||||
<name>Keycloak SAML Adapter Core</name>
|
||||
<name>Keycloak SAML Client Adapter Core</name>
|
||||
<description/>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
package org.keycloak.adapters.saml;
|
||||
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.adapters.saml.config.IDP;
|
||||
import org.keycloak.enums.SslRequired;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DefaultSamlDeployment implements SamlDeployment {
|
||||
|
||||
public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
|
||||
private boolean signRequest;
|
||||
private boolean validateResponseSignature;
|
||||
private String signatureCanonicalizationMethod;
|
||||
private Binding requestBinding;
|
||||
private Binding responseBinding;
|
||||
private String requestBindingUrl;
|
||||
|
||||
@Override
|
||||
public boolean signRequest() {
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateResponseSignature() {
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignatureCanonicalizationMethod() {
|
||||
return signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Binding getRequestBinding() {
|
||||
return requestBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Binding getResponseBinding() {
|
||||
return responseBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestBindingUrl() {
|
||||
return requestBindingUrl;
|
||||
}
|
||||
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
|
||||
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public void setRequestBinding(Binding requestBinding) {
|
||||
this.requestBinding = requestBinding;
|
||||
}
|
||||
|
||||
public void setResponseBinding(Binding responseBinding) {
|
||||
this.responseBinding = responseBinding;
|
||||
}
|
||||
|
||||
public void setRequestBindingUrl(String requestBindingUrl) {
|
||||
this.requestBindingUrl = requestBindingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultSingleLogoutService implements IDP.SingleLogoutService {
|
||||
private boolean validateRequestSignature;
|
||||
private boolean validateResponseSignature;
|
||||
private boolean signRequest;
|
||||
private boolean signResponse;
|
||||
private String signatureCanonicalizationMethod;
|
||||
private Binding requestBinding;
|
||||
private Binding responseBinding;
|
||||
private String requestBindingUrl;
|
||||
private String responseBindingUrl;
|
||||
|
||||
@Override
|
||||
public boolean validateRequestSignature() {
|
||||
return validateRequestSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateResponseSignature() {
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signRequest() {
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signResponse() {
|
||||
return signResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignatureCanonicalizationMethod() {
|
||||
return signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Binding getRequestBinding() {
|
||||
return requestBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Binding getResponseBinding() {
|
||||
return responseBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestBindingUrl() {
|
||||
return requestBindingUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResponseBindingUrl() {
|
||||
return responseBindingUrl;
|
||||
}
|
||||
|
||||
public void setValidateRequestSignature(boolean validateRequestSignature) {
|
||||
this.validateRequestSignature = validateRequestSignature;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public void setSignResponse(boolean signResponse) {
|
||||
this.signResponse = signResponse;
|
||||
}
|
||||
|
||||
public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
|
||||
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public void setRequestBinding(Binding requestBinding) {
|
||||
this.requestBinding = requestBinding;
|
||||
}
|
||||
|
||||
public void setResponseBinding(Binding responseBinding) {
|
||||
this.responseBinding = responseBinding;
|
||||
}
|
||||
|
||||
public void setRequestBindingUrl(String requestBindingUrl) {
|
||||
this.requestBindingUrl = requestBindingUrl;
|
||||
}
|
||||
|
||||
public void setResponseBindingUrl(String responseBindingUrl) {
|
||||
this.responseBindingUrl = responseBindingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class DefaultIDP implements IDP {
|
||||
|
||||
|
||||
|
||||
private String entityID;
|
||||
private PublicKey signatureValidationKey;
|
||||
private SingleSignOnService singleSignOnService;
|
||||
private SingleLogoutService singleLogoutService;
|
||||
|
||||
@Override
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleSignOnService getSingleSignOnService() {
|
||||
return singleSignOnService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleLogoutService getSingleLogoutService() {
|
||||
return singleLogoutService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKey getSignatureValidationKey() {
|
||||
return signatureValidationKey;
|
||||
}
|
||||
|
||||
public void setEntityID(String entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
public void setSignatureValidationKey(PublicKey signatureValidationKey) {
|
||||
this.signatureValidationKey = signatureValidationKey;
|
||||
}
|
||||
|
||||
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
||||
this.singleSignOnService = singleSignOnService;
|
||||
}
|
||||
|
||||
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
||||
this.singleLogoutService = singleLogoutService;
|
||||
}
|
||||
}
|
||||
|
||||
private IDP idp;
|
||||
private boolean configured;
|
||||
private SslRequired sslRequired = SslRequired.EXTERNAL;
|
||||
private String entityID;
|
||||
private String nameIDPolicyFormat;
|
||||
private boolean forceAuthentication;
|
||||
private PrivateKey decryptionKey;
|
||||
private KeyPair signingKeyPair;
|
||||
private String assertionConsumerServiceUrl;
|
||||
private Set<String> roleAttributeNames;
|
||||
private Set<String> roleFriendlyAttributeNames;
|
||||
private PrincipalNamePolicy principalNamePolicy = PrincipalNamePolicy.FROM_NAME_ID;
|
||||
private String principalAttributeName;
|
||||
private String logoutPage;
|
||||
|
||||
|
||||
@Override
|
||||
public IDP getIDP() {
|
||||
return idp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigured() {
|
||||
return configured;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslRequired getSslRequired() {
|
||||
return sslRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameIDPolicyFormat() {
|
||||
return nameIDPolicyFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceAuthentication() {
|
||||
return forceAuthentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getDecryptionKey() {
|
||||
return decryptionKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair getSigningKeyPair() {
|
||||
return signingKeyPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssertionConsumerServiceUrl() {
|
||||
return assertionConsumerServiceUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoleAttributeNames() {
|
||||
return roleAttributeNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoleAttributeFriendlyNames() {
|
||||
return roleFriendlyAttributeNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrincipalNamePolicy getPrincipalNamePolicy() {
|
||||
return principalNamePolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrincipalAttributeName() {
|
||||
return principalAttributeName;
|
||||
}
|
||||
|
||||
public void setIdp(IDP idp) {
|
||||
this.idp = idp;
|
||||
}
|
||||
|
||||
public void setConfigured(boolean configured) {
|
||||
this.configured = configured;
|
||||
}
|
||||
|
||||
public void setSslRequired(SslRequired sslRequired) {
|
||||
this.sslRequired = sslRequired;
|
||||
}
|
||||
|
||||
public void setEntityID(String entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
|
||||
this.nameIDPolicyFormat = nameIDPolicyFormat;
|
||||
}
|
||||
|
||||
public void setForceAuthentication(boolean forceAuthentication) {
|
||||
this.forceAuthentication = forceAuthentication;
|
||||
}
|
||||
|
||||
public void setDecryptionKey(PrivateKey decryptionKey) {
|
||||
this.decryptionKey = decryptionKey;
|
||||
}
|
||||
|
||||
public void setSigningKeyPair(KeyPair signingKeyPair) {
|
||||
this.signingKeyPair = signingKeyPair;
|
||||
}
|
||||
|
||||
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
||||
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
||||
}
|
||||
|
||||
public void setRoleAttributeNames(Set<String> roleAttributeNames) {
|
||||
this.roleAttributeNames = roleAttributeNames;
|
||||
}
|
||||
|
||||
public void setRoleFriendlyAttributeNames(Set<String> roleFriendlyAttributeNames) {
|
||||
this.roleFriendlyAttributeNames = roleFriendlyAttributeNames;
|
||||
}
|
||||
|
||||
public void setPrincipalNamePolicy(PrincipalNamePolicy principalNamePolicy) {
|
||||
this.principalNamePolicy = principalNamePolicy;
|
||||
}
|
||||
|
||||
public void setPrincipalAttributeName(String principalAttributeName) {
|
||||
this.principalAttributeName = principalAttributeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogoutPage() {
|
||||
return logoutPage;
|
||||
}
|
||||
|
||||
public void setLogoutPage(String logoutPage) {
|
||||
this.logoutPage = logoutPage;
|
||||
}
|
||||
}
|
|
@ -34,8 +34,8 @@ public class InitiateLogin implements AuthChallenge {
|
|||
@Override
|
||||
public boolean challenge(HttpFacade httpFacade) {
|
||||
try {
|
||||
String issuerURL = deployment.getIssuer();
|
||||
String actionUrl = deployment.getSingleSignOnServiceUrl();
|
||||
String issuerURL = deployment.getEntityID();
|
||||
String actionUrl = deployment.getIDP().getSingleSignOnService().getRequestBindingUrl();
|
||||
String destinationUrl = actionUrl;
|
||||
String nameIDPolicyFormat = deployment.getNameIDPolicyFormat();
|
||||
|
||||
|
@ -45,28 +45,30 @@ public class InitiateLogin implements AuthChallenge {
|
|||
|
||||
String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
|
||||
|
||||
if (deployment.getResponseBinding() == SamlDeployment.Binding.POST) {
|
||||
if (deployment.getIDP().getSingleSignOnService().getResponseBinding() == SamlDeployment.Binding.POST) {
|
||||
protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
|
||||
}
|
||||
|
||||
SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
|
||||
.assertionConsumerUrl(deployment.getAssertionConsumerServiceUrl())
|
||||
.destination(destinationUrl)
|
||||
.issuer(issuerURL)
|
||||
.forceAuthn(deployment.isForceAuthentication())
|
||||
.protocolBinding(protocolBinding)
|
||||
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat));
|
||||
if (deployment.getAssertionConsumerServiceUrl() != null) {
|
||||
authnRequestBuilder.assertionConsumerUrl(deployment.getAssertionConsumerServiceUrl());
|
||||
}
|
||||
BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
|
||||
|
||||
if (deployment.isRequestsSigned()) {
|
||||
if (deployment.getIDP().getSingleSignOnService().signRequest()) {
|
||||
|
||||
|
||||
KeyPair keypair = deployment.getSigningKeyPair();
|
||||
if (keypair == null) {
|
||||
throw new RuntimeException("Signing keys not configured");
|
||||
}
|
||||
if (deployment.getSignatureCanonicalizationMethod() != null) {
|
||||
binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
|
||||
if (deployment.getIDP().getSingleSignOnService().getSignatureCanonicalizationMethod() != null) {
|
||||
binding.canonicalizationMethod(deployment.getIDP().getSingleSignOnService().getSignatureCanonicalizationMethod());
|
||||
}
|
||||
|
||||
binding.signWith(keypair);
|
||||
|
@ -75,7 +77,7 @@ public class InitiateLogin implements AuthChallenge {
|
|||
sessionStore.saveRequest();
|
||||
|
||||
Document document = authnRequestBuilder.toDocument();
|
||||
SamlDeployment.Binding samlBinding = deployment.getRequestBinding();
|
||||
SamlDeployment.Binding samlBinding = deployment.getIDP().getSingleSignOnService().getRequestBinding();
|
||||
SamlUtil.sendSaml(httpFacade, actionUrl, binding, document, samlBinding);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not create authentication request.", e);
|
||||
|
|
|
@ -90,12 +90,12 @@ public abstract class SamlAuthenticator {
|
|||
SamlSession account = sessionStore.getAccount();
|
||||
SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
|
||||
.assertionExpiration(30)
|
||||
.issuer(deployment.getIssuer())
|
||||
.issuer(deployment.getEntityID())
|
||||
.sessionIndex(account.getSessionIndex())
|
||||
.userPrincipal(account.getPrincipal().getSamlSubject(), account.getPrincipal().getNameIDFormat())
|
||||
.destination(deployment.getSingleLogoutServiceUrl());
|
||||
.destination(deployment.getIDP().getSingleLogoutService().getRequestBindingUrl());
|
||||
BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
|
||||
if (deployment.isRequestsSigned()) {
|
||||
if (deployment.getIDP().getSingleLogoutService().signRequest()) {
|
||||
binding.signWith(deployment.getSigningKeyPair())
|
||||
.signDocument();
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public abstract class SamlAuthenticator {
|
|||
binding.relayState("logout");
|
||||
|
||||
try {
|
||||
SamlUtil.sendSaml(facade, deployment.getSingleLogoutServiceUrl(), binding, logoutBuilder.buildDocument(), deployment.getRequestBinding());
|
||||
SamlUtil.sendSaml(facade, deployment.getIDP().getSingleLogoutService().getRequestBindingUrl(), binding, logoutBuilder.buildDocument(), deployment.getIDP().getSingleLogoutService().getRequestBinding());
|
||||
} catch (ProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ConfigurationException e) {
|
||||
|
@ -129,9 +129,11 @@ public abstract class SamlAuthenticator {
|
|||
if (!facade.getRequest().getURI().toString().equals(requestAbstractType.getDestination())) {
|
||||
throw new RuntimeException("destination not equal to request");
|
||||
}
|
||||
validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
|
||||
|
||||
if (requestAbstractType instanceof LogoutRequestType) {
|
||||
if (deployment.getIDP().getSingleLogoutService().validateRequestSignature()) {
|
||||
validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
|
||||
}
|
||||
LogoutRequestType logout = (LogoutRequestType) requestAbstractType;
|
||||
return logoutRequest(logout, relayState);
|
||||
|
||||
|
@ -147,21 +149,22 @@ public abstract class SamlAuthenticator {
|
|||
sessionStore.logoutBySsoId(request.getSessionIndex());
|
||||
}
|
||||
|
||||
String issuerURL = deployment.getIssuer();
|
||||
String issuerURL = deployment.getEntityID();
|
||||
SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
|
||||
builder.logoutRequestID(request.getID());
|
||||
builder.destination(deployment.getSingleLogoutServiceUrl());
|
||||
builder.destination(deployment.getIDP().getSingleLogoutService().getResponseBindingUrl());
|
||||
builder.issuer(issuerURL);
|
||||
BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder().relayState(relayState);
|
||||
if (deployment.isRequestsSigned()) {
|
||||
if (deployment.getIDP().getSingleLogoutService().signResponse()) {
|
||||
binding.signWith(deployment.getSigningKeyPair())
|
||||
.signDocument();
|
||||
binding.canonicalizationMethod(deployment.getIDP().getSingleLogoutService().getSignatureCanonicalizationMethod());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
SamlUtil.sendSaml(facade, deployment.getSingleLogoutServiceUrl(), binding, builder.buildDocument(),
|
||||
deployment.getResponseBinding());
|
||||
SamlUtil.sendSaml(facade, deployment.getIDP().getSingleLogoutService().getResponseBindingUrl(), binding, builder.buildDocument(),
|
||||
deployment.getIDP().getSingleLogoutService().getResponseBinding());
|
||||
} catch (ConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ProcessingException e) {
|
||||
|
@ -188,11 +191,16 @@ public abstract class SamlAuthenticator {
|
|||
if (!facade.getRequest().getURI().toString().equals(statusResponse.getDestination())) {
|
||||
throw new RuntimeException("destination not equal to request");
|
||||
}
|
||||
validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY);
|
||||
if (statusResponse instanceof ResponseType) {
|
||||
if (deployment.getIDP().getSingleSignOnService().validateResponseSignature()) {
|
||||
validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
|
||||
}
|
||||
return handleLoginResponse((ResponseType)statusResponse);
|
||||
|
||||
} else {
|
||||
if (deployment.getIDP().getSingleLogoutService().validateResponseSignature()) {
|
||||
validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
|
||||
}
|
||||
// todo need to check that it is actually a LogoutResponse
|
||||
return handleLogoutResponse(holder, statusResponse, relayState);
|
||||
}
|
||||
|
@ -200,24 +208,22 @@ public abstract class SamlAuthenticator {
|
|||
}
|
||||
|
||||
private void validateSamlSignature(SAMLDocumentHolder holder, boolean postBinding, String paramKey) {
|
||||
if (deployment.isValidateSignatures()) {
|
||||
try {
|
||||
if (postBinding) {
|
||||
verifyPostBindingSignature(holder.getSamlDocument(), deployment.getSignatureValidationKey());
|
||||
verifyPostBindingSignature(holder.getSamlDocument(), deployment.getIDP().getSignatureValidationKey());
|
||||
} else {
|
||||
verifyRedirectBindingSignature(deployment.getSignatureValidationKey(), paramKey);
|
||||
verifyRedirectBindingSignature(deployment.getIDP().getSignatureValidationKey(), paramKey);
|
||||
}
|
||||
} catch (VerificationException e) {
|
||||
log.error("validation failed", e);
|
||||
throw new RuntimeException("invalid document signature");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected AuthOutcome handleLoginResponse(ResponseType responseType) {
|
||||
AssertionType assertion = null;
|
||||
try {
|
||||
assertion = AssertionUtil.getAssertion(responseType, deployment.getAssertionDecryptionKey());
|
||||
assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
|
||||
if (AssertionUtil.hasExpired(assertion)) {
|
||||
return initiateLogin();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.keycloak.adapters.HttpFacade.Request;
|
||||
|
||||
/**
|
||||
* On multi-tenant scenarios, Keycloak will defer the resolution of a
|
||||
* SamlDeployment to the target application at the request-phase.
|
||||
*
|
||||
* A Request object is passed to the resolver and callers expect a complete
|
||||
* SamlDeployment. Based on this SamlDeployment, Keycloak will resume
|
||||
* authenticating and authorizing the request.
|
||||
*
|
||||
* The easiest way to build a SamlDeployment is to use
|
||||
* DeploymentBuilder , passing the InputStream of an existing
|
||||
* keycloak-saml.xml to the build() method.
|
||||
*
|
||||
* @author Juraci Paixão Kröhling <juraci at kroehling.de>
|
||||
*/
|
||||
public interface SamlConfigResolver {
|
||||
|
||||
public SamlDeployment resolve(Request facade);
|
||||
|
||||
}
|
|
@ -14,26 +14,53 @@ import java.util.Set;
|
|||
public interface SamlDeployment {
|
||||
enum Binding {
|
||||
POST,
|
||||
REDIRECT
|
||||
REDIRECT;
|
||||
|
||||
public static Binding parseBinding(String val) {
|
||||
if (val == null) return POST;
|
||||
return Binding.valueOf(val);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDP {
|
||||
String getEntityID();
|
||||
|
||||
SingleSignOnService getSingleSignOnService();
|
||||
SingleLogoutService getSingleLogoutService();
|
||||
PublicKey getSignatureValidationKey();
|
||||
|
||||
public interface SingleSignOnService {
|
||||
boolean signRequest();
|
||||
boolean validateResponseSignature();
|
||||
String getSignatureCanonicalizationMethod();
|
||||
Binding getRequestBinding();
|
||||
Binding getResponseBinding();
|
||||
String getRequestBindingUrl();
|
||||
}
|
||||
public interface SingleLogoutService {
|
||||
boolean validateRequestSignature();
|
||||
boolean validateResponseSignature();
|
||||
boolean signRequest();
|
||||
boolean signResponse();
|
||||
String getSignatureCanonicalizationMethod();
|
||||
Binding getRequestBinding();
|
||||
Binding getResponseBinding();
|
||||
String getRequestBindingUrl();
|
||||
String getResponseBindingUrl();
|
||||
}
|
||||
}
|
||||
|
||||
public IDP getIDP();
|
||||
|
||||
public boolean isConfigured();
|
||||
SslRequired getSslRequired();
|
||||
String getSingleSignOnServiceUrl();
|
||||
String getSingleLogoutServiceUrl();
|
||||
String getIssuer();
|
||||
String getEntityID();
|
||||
String getNameIDPolicyFormat();
|
||||
String getAssertionConsumerServiceUrl();
|
||||
Binding getRequestBinding();
|
||||
Binding getResponseBinding();
|
||||
KeyPair getSigningKeyPair();
|
||||
String getSignatureCanonicalizationMethod();
|
||||
boolean isForceAuthentication();
|
||||
boolean isRequestsSigned();
|
||||
|
||||
boolean isValidateSignatures();
|
||||
PublicKey getSignatureValidationKey();
|
||||
PrivateKey getAssertionDecryptionKey();
|
||||
PrivateKey getDecryptionKey();
|
||||
KeyPair getSigningKeyPair();
|
||||
String getAssertionConsumerServiceUrl();
|
||||
String getLogoutPage();
|
||||
|
||||
Set<String> getRoleAttributeNames();
|
||||
Set<String> getRoleAttributeFriendlyNames();
|
||||
|
|
|
@ -7,7 +7,13 @@ import org.keycloak.adapters.HttpFacade;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SamlDeploymentContext {
|
||||
private SamlDeployment deployment = null;
|
||||
|
||||
public SamlDeploymentContext(SamlDeployment deployment) {
|
||||
this.deployment = deployment;
|
||||
}
|
||||
|
||||
public SamlDeployment resolveDeployment(HttpFacade facade) {
|
||||
return null;
|
||||
return deployment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SamlPrincipal implements Serializable, Principal {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
package org.keycloak.adapters.saml.config;
|
||||
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class IDP implements Serializable {
|
||||
public static class SingleSignOnService implements Serializable {
|
||||
private boolean signRequest;
|
||||
private boolean validateResponseSignature;
|
||||
private String signatureCanonicalizationMethod;
|
||||
private String requestBinding;
|
||||
private String responseBinding;
|
||||
private String bindingUrl;
|
||||
|
||||
public boolean isSignRequest() {
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public boolean isValidateResponseSignature() {
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public String getSignatureCanonicalizationMethod() {
|
||||
return signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
|
||||
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public String getRequestBinding() {
|
||||
return requestBinding;
|
||||
}
|
||||
|
||||
public void setRequestBinding(String requestBinding) {
|
||||
this.requestBinding = requestBinding;
|
||||
}
|
||||
|
||||
public String getResponseBinding() {
|
||||
return responseBinding;
|
||||
}
|
||||
|
||||
public void setResponseBinding(String responseBinding) {
|
||||
this.responseBinding = responseBinding;
|
||||
}
|
||||
|
||||
public String getBindingUrl() {
|
||||
return bindingUrl;
|
||||
}
|
||||
|
||||
public void setBindingUrl(String bindingUrl) {
|
||||
this.bindingUrl = bindingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SingleLogoutService implements Serializable {
|
||||
private boolean signRequest;
|
||||
private boolean signResponse;
|
||||
private boolean validateRequestSignature;
|
||||
private boolean validateResponseSignature;
|
||||
private String signatureCanonicalizationMethod;
|
||||
private String requestBinding;
|
||||
private String responseBinding;
|
||||
private String postBindingUrl;
|
||||
private String redirectBindingUrl;
|
||||
|
||||
public boolean isSignRequest() {
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public boolean isSignResponse() {
|
||||
return signResponse;
|
||||
}
|
||||
|
||||
public void setSignResponse(boolean signResponse) {
|
||||
this.signResponse = signResponse;
|
||||
}
|
||||
|
||||
public boolean isValidateRequestSignature() {
|
||||
return validateRequestSignature;
|
||||
}
|
||||
|
||||
public void setValidateRequestSignature(boolean validateRequestSignature) {
|
||||
this.validateRequestSignature = validateRequestSignature;
|
||||
}
|
||||
|
||||
public boolean isValidateResponseSignature() {
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public String getSignatureCanonicalizationMethod() {
|
||||
return signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
|
||||
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public String getRequestBinding() {
|
||||
return requestBinding;
|
||||
}
|
||||
|
||||
public void setRequestBinding(String requestBinding) {
|
||||
this.requestBinding = requestBinding;
|
||||
}
|
||||
|
||||
public String getResponseBinding() {
|
||||
return responseBinding;
|
||||
}
|
||||
|
||||
public void setResponseBinding(String responseBinding) {
|
||||
this.responseBinding = responseBinding;
|
||||
}
|
||||
|
||||
public String getPostBindingUrl() {
|
||||
return postBindingUrl;
|
||||
}
|
||||
|
||||
public void setPostBindingUrl(String postBindingUrl) {
|
||||
this.postBindingUrl = postBindingUrl;
|
||||
}
|
||||
|
||||
public String getRedirectBindingUrl() {
|
||||
return redirectBindingUrl;
|
||||
}
|
||||
|
||||
public void setRedirectBindingUrl(String redirectBindingUrl) {
|
||||
this.redirectBindingUrl = redirectBindingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
private String entityID;
|
||||
private SingleSignOnService singleSignOnService;
|
||||
private SingleLogoutService singleLogoutService;
|
||||
private List<Key> keys;
|
||||
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
public void setEntityID(String entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
public SingleSignOnService getSingleSignOnService() {
|
||||
return singleSignOnService;
|
||||
}
|
||||
|
||||
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
||||
this.singleSignOnService = singleSignOnService;
|
||||
}
|
||||
|
||||
public SingleLogoutService getSingleLogoutService() {
|
||||
return singleLogoutService;
|
||||
}
|
||||
|
||||
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
||||
this.singleLogoutService = singleLogoutService;
|
||||
}
|
||||
|
||||
public List<Key> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public void setKeys(List<Key> keys) {
|
||||
this.keys = keys;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package org.keycloak.adapters.saml.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class Key implements Serializable {
|
||||
|
||||
public static class KeyStoreConfig implements Serializable {
|
||||
private String file;
|
||||
private String resource;
|
||||
private String password;
|
||||
private String type;
|
||||
private String alias;
|
||||
private String privateKeyAlias;
|
||||
private String privateKeyPassword;
|
||||
private String certificateAlias;
|
||||
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPrivateKeyAlias() {
|
||||
return privateKeyAlias;
|
||||
}
|
||||
|
||||
public void setPrivateKeyAlias(String privateKeyAlias) {
|
||||
this.privateKeyAlias = privateKeyAlias;
|
||||
}
|
||||
|
||||
public String getPrivateKeyPassword() {
|
||||
return privateKeyPassword;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||
this.privateKeyPassword = privateKeyPassword;
|
||||
}
|
||||
|
||||
public String getCertificateAlias() {
|
||||
return certificateAlias;
|
||||
}
|
||||
|
||||
public void setCertificateAlias(String certificateAlias) {
|
||||
this.certificateAlias = certificateAlias;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean signing;
|
||||
private boolean encryption;
|
||||
private KeyStoreConfig keystore;
|
||||
private String privateKeyPem;
|
||||
private String publicKeyPem;
|
||||
private String certificatePem;
|
||||
|
||||
|
||||
public boolean isSigning() {
|
||||
return signing;
|
||||
}
|
||||
|
||||
public void setSigning(boolean signing) {
|
||||
this.signing = signing;
|
||||
}
|
||||
|
||||
public boolean isEncryption() {
|
||||
return encryption;
|
||||
}
|
||||
|
||||
public void setEncryption(boolean encryption) {
|
||||
this.encryption = encryption;
|
||||
}
|
||||
|
||||
public KeyStoreConfig getKeystore() {
|
||||
return keystore;
|
||||
}
|
||||
|
||||
public void setKeystore(KeyStoreConfig keystore) {
|
||||
this.keystore = keystore;
|
||||
}
|
||||
|
||||
public String getPrivateKeyPem() {
|
||||
return privateKeyPem;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPem(String privateKeyPem) {
|
||||
this.privateKeyPem = privateKeyPem;
|
||||
}
|
||||
|
||||
public String getPublicKeyPem() {
|
||||
return publicKeyPem;
|
||||
}
|
||||
|
||||
public void setPublicKeyPem(String publicKeyPem) {
|
||||
this.publicKeyPem = publicKeyPem;
|
||||
}
|
||||
|
||||
public String getCertificatePem() {
|
||||
return certificatePem;
|
||||
}
|
||||
|
||||
public void setCertificatePem(String certificatePem) {
|
||||
this.certificatePem = certificatePem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.keycloak.adapters.saml.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakSamlAdapter implements Serializable {
|
||||
private List<SP> sps = new LinkedList<>();
|
||||
|
||||
public List<SP> getSps() {
|
||||
return sps;
|
||||
}
|
||||
|
||||
public void setSps(List<SP> sps) {
|
||||
this.sps = sps;
|
||||
}
|
||||
}
|
126
saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
Executable file
126
saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
Executable file
|
@ -0,0 +1,126 @@
|
|||
package org.keycloak.adapters.saml.config;
|
||||
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.enums.SslRequired;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SP implements Serializable {
|
||||
public static class PrincipalNameMapping implements Serializable {
|
||||
private String policy;
|
||||
private String attributeName;
|
||||
|
||||
public String getPolicy() {
|
||||
return policy;
|
||||
}
|
||||
|
||||
public void setPolicy(String policy) {
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
public String getAttributeName() {
|
||||
return attributeName;
|
||||
}
|
||||
|
||||
public void setAttributeName(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
}
|
||||
|
||||
private String entityID;
|
||||
private String sslPolicy;
|
||||
private boolean forceAuthentication;
|
||||
private String logoutPage;
|
||||
private List<Key> keys;
|
||||
private String nameIDPolicyFormat;
|
||||
private PrincipalNameMapping principalNameMapping;
|
||||
private Set<String> roleAttributes;
|
||||
private Set<String> roleFriendlyAttributes;
|
||||
private IDP idp;
|
||||
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
public void setEntityID(String entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
public String getSslPolicy() {
|
||||
return sslPolicy;
|
||||
}
|
||||
|
||||
public void setSslPolicy(String sslPolicy) {
|
||||
this.sslPolicy = sslPolicy;
|
||||
}
|
||||
|
||||
public boolean isForceAuthentication() {
|
||||
return forceAuthentication;
|
||||
}
|
||||
|
||||
public void setForceAuthentication(boolean forceAuthentication) {
|
||||
this.forceAuthentication = forceAuthentication;
|
||||
}
|
||||
|
||||
public List<Key> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public void setKeys(List<Key> keys) {
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
public String getNameIDPolicyFormat() {
|
||||
return nameIDPolicyFormat;
|
||||
}
|
||||
|
||||
public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
|
||||
this.nameIDPolicyFormat = nameIDPolicyFormat;
|
||||
}
|
||||
|
||||
public PrincipalNameMapping getPrincipalNameMapping() {
|
||||
return principalNameMapping;
|
||||
}
|
||||
|
||||
public void setPrincipalNameMapping(PrincipalNameMapping principalNameMapping) {
|
||||
this.principalNameMapping = principalNameMapping;
|
||||
}
|
||||
|
||||
public Set<String> getRoleAttributes() {
|
||||
return roleAttributes;
|
||||
}
|
||||
|
||||
public void setRoleAttributes(Set<String> roleAttributes) {
|
||||
this.roleAttributes = roleAttributes;
|
||||
}
|
||||
|
||||
public Set<String> getRoleFriendlyAttributes() {
|
||||
return roleFriendlyAttributes;
|
||||
}
|
||||
|
||||
public void setRoleFriendlyAttributes(Set<String> roleFriendlyAttributes) {
|
||||
this.roleFriendlyAttributes = roleFriendlyAttributes;
|
||||
}
|
||||
|
||||
public IDP getIdp() {
|
||||
return idp;
|
||||
}
|
||||
|
||||
public void setIdp(IDP idp) {
|
||||
this.idp = idp;
|
||||
}
|
||||
|
||||
public String getLogoutPage() {
|
||||
return logoutPage;
|
||||
}
|
||||
|
||||
public void setLogoutPage(String logoutPage) {
|
||||
this.logoutPage = logoutPage;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
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 LOGOUT_PAGE_ATTR = "logoutPage";
|
||||
|
||||
|
||||
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_MAPPING_ELEMENT = "RoleMapping";
|
||||
public static final String ATTRIBUTE_ELEMENT = "Attribute";
|
||||
public static final String FRIENDLY_ATTRIBUTE_ELEMENT = "FriendlyAttribute";
|
||||
public static final String NAME_ATTR = "name";
|
||||
|
||||
public static final String IDP_ELEMENT = "IDP";
|
||||
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 SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod";
|
||||
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_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
|
||||
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
||||
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.DefaultSamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
|
||||
import org.keycloak.adapters.saml.config.SP;
|
||||
import org.keycloak.enums.SslRequired;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.util.PemUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DeploymentBuilder {
|
||||
public SamlDeployment build(InputStream xml, ResourceLoader resourceLoader) throws ParsingException {
|
||||
DefaultSamlDeployment deployment = new DefaultSamlDeployment();
|
||||
DefaultSamlDeployment.DefaultIDP idp = new DefaultSamlDeployment.DefaultIDP();
|
||||
DefaultSamlDeployment.DefaultSingleSignOnService sso = new DefaultSamlDeployment.DefaultSingleSignOnService();
|
||||
DefaultSamlDeployment.DefaultSingleLogoutService slo = new DefaultSamlDeployment.DefaultSingleLogoutService();
|
||||
idp.setSingleSignOnService(sso);
|
||||
idp.setSingleLogoutService(slo);
|
||||
|
||||
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
|
||||
SP sp = adapter.getSps().get(0);
|
||||
deployment.setConfigured(true);
|
||||
deployment.setEntityID(sp.getEntityID());
|
||||
deployment.setForceAuthentication(sp.isForceAuthentication());
|
||||
deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat());
|
||||
deployment.setLogoutPage(sp.getLogoutPage());
|
||||
if (sp.getPrincipalNameMapping() != null) {
|
||||
SamlDeployment.PrincipalNamePolicy policy = SamlDeployment.PrincipalNamePolicy.valueOf(sp.getPrincipalNameMapping().getPolicy());
|
||||
deployment.setPrincipalNamePolicy(policy);
|
||||
deployment.setPrincipalAttributeName(sp.getPrincipalNameMapping().getAttributeName());
|
||||
}
|
||||
deployment.setRoleAttributeNames(sp.getRoleAttributes());
|
||||
deployment.setRoleFriendlyAttributeNames(sp.getRoleFriendlyAttributes());
|
||||
if (sp.getSslPolicy() != null) {
|
||||
SslRequired ssl = SslRequired.valueOf(sp.getSslPolicy());
|
||||
deployment.setSslRequired(ssl);
|
||||
}
|
||||
for (Key key : sp.getKeys()) {
|
||||
if (key.isSigning()) {
|
||||
PrivateKey privateKey = null;
|
||||
PublicKey publicKey = null;
|
||||
if (key.getKeystore() != null) {
|
||||
KeyStore keyStore = loadKeystore(resourceLoader, key);
|
||||
Certificate cert = null;
|
||||
try {
|
||||
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
|
||||
privateKey = (PrivateKey)keyStore.getKey(key.getKeystore().getPrivateKeyAlias(), key.getKeystore().getPrivateKeyPassword().toCharArray());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
publicKey = cert.getPublicKey();
|
||||
} else {
|
||||
if (key.getPrivateKeyPem() == null) {
|
||||
throw new RuntimeException("SP signing key must have a PrivateKey defined");
|
||||
}
|
||||
try {
|
||||
privateKey = PemUtils.decodePrivateKey(key.getPrivateKeyPem().trim());
|
||||
if (key.getPublicKeyPem() == null &&key.getCertificatePem() == null) {
|
||||
throw new RuntimeException("Sp signing key must have a PublicKey or Certificate defined");
|
||||
}
|
||||
publicKey = getPublicKeyFromPem(key);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
KeyPair keyPair = new KeyPair(publicKey, privateKey);
|
||||
deployment.setSigningKeyPair(keyPair);
|
||||
|
||||
} else if (key.isEncryption()) {
|
||||
KeyStore keyStore = loadKeystore(resourceLoader, key);
|
||||
try {
|
||||
PrivateKey privateKey = (PrivateKey)keyStore.getKey(key.getKeystore().getPrivateKeyAlias(), key.getKeystore().getPrivateKeyPassword().toCharArray());
|
||||
deployment.setDecryptionKey(privateKey);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deployment.setIdp(idp);
|
||||
idp.setEntityID(sp.getIdp().getEntityID());
|
||||
sso.setRequestBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleSignOnService().getRequestBinding()));
|
||||
sso.setRequestBindingUrl(sp.getIdp().getSingleSignOnService().getBindingUrl());
|
||||
sso.setResponseBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleSignOnService().getResponseBinding()));
|
||||
sso.setSignatureCanonicalizationMethod(sp.getIdp().getSingleSignOnService().getSignatureCanonicalizationMethod());
|
||||
sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
|
||||
sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
|
||||
|
||||
slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
|
||||
slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
|
||||
slo.setValidateResponseSignature(sp.getIdp().getSingleLogoutService().isValidateResponseSignature());
|
||||
slo.setValidateRequestSignature(sp.getIdp().getSingleLogoutService().isValidateRequestSignature());
|
||||
slo.setSignatureCanonicalizationMethod(sp.getIdp().getSingleLogoutService().getSignatureCanonicalizationMethod());
|
||||
slo.setRequestBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleLogoutService().getRequestBinding()));
|
||||
slo.setResponseBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleLogoutService().getResponseBinding()));
|
||||
if (slo.getRequestBinding() == SamlDeployment.Binding.POST) {
|
||||
slo.setRequestBindingUrl(sp.getIdp().getSingleLogoutService().getPostBindingUrl());
|
||||
} else {
|
||||
slo.setRequestBindingUrl(sp.getIdp().getSingleLogoutService().getRedirectBindingUrl());
|
||||
}
|
||||
if (slo.getResponseBinding() == SamlDeployment.Binding.POST) {
|
||||
slo.setResponseBindingUrl(sp.getIdp().getSingleLogoutService().getPostBindingUrl());
|
||||
} else {
|
||||
slo.setResponseBindingUrl(sp.getIdp().getSingleLogoutService().getRedirectBindingUrl());
|
||||
}
|
||||
for (Key key : sp.getIdp().getKeys()) {
|
||||
if (key.isSigning()) {
|
||||
if (key.getKeystore() != null) {
|
||||
KeyStore keyStore = loadKeystore(resourceLoader, key);
|
||||
Certificate cert = null;
|
||||
try {
|
||||
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
|
||||
} catch (KeyStoreException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
idp.setSignatureValidationKey(cert.getPublicKey());
|
||||
} else {
|
||||
if (key.getPublicKeyPem() == null && key.getCertificatePem() == null) {
|
||||
throw new RuntimeException("IDP signing key must have a PublicKey or Certificate defined");
|
||||
}
|
||||
try {
|
||||
PublicKey publicKey = getPublicKeyFromPem(key);
|
||||
idp.setSignatureValidationKey(publicKey);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
protected static PublicKey getPublicKeyFromPem(Key key) throws Exception {
|
||||
PublicKey publicKey;
|
||||
if (key.getPublicKeyPem() != null) {
|
||||
publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim());
|
||||
} else {
|
||||
Certificate cert = PemUtils.decodeCertificate(key.getCertificatePem().trim());
|
||||
publicKey = cert.getPublicKey();
|
||||
}
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
protected static KeyStore loadKeystore(ResourceLoader resourceLoader, Key key) {
|
||||
String type = key.getKeystore().getType();
|
||||
if (type == null) type = "JKS";
|
||||
KeyStore keyStore = null;
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(type);
|
||||
} catch (KeyStoreException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
InputStream is = null;
|
||||
if (key.getKeystore().getFile() != null) {
|
||||
File fp = new File(key.getKeystore().getFile());
|
||||
if (!fp.exists()) {
|
||||
}
|
||||
try {
|
||||
is = new FileInputStream(fp);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException("KeyStore " + key.getKeystore().getFile() + " does not exist");
|
||||
}
|
||||
|
||||
} else {
|
||||
is = resourceLoader.getResourceAsStream(key.getKeystore().getResource());
|
||||
if (is == null) {
|
||||
throw new RuntimeException("KeyStore " + key.getKeystore().getResource() + " does not exist");
|
||||
}
|
||||
}
|
||||
try {
|
||||
keyStore.load(is, key.getKeystore().getPassword().toCharArray());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
* @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 = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
||||
if (entityID == null) {
|
||||
throw new ParsingException("entityID must be set on IDP");
|
||||
|
||||
}
|
||||
idp.setEntityID(entityID);
|
||||
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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.IDP_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
|
||||
IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader);
|
||||
idp.setSingleSignOnService(sso);
|
||||
|
||||
} else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
|
||||
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader);
|
||||
idp.setSingleLogoutService(slo);
|
||||
|
||||
} 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) throws ParsingException {
|
||||
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
slo.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR));
|
||||
slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR));
|
||||
slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR));
|
||||
slo.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
||||
slo.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
slo.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
slo.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR));
|
||||
slo.setPostBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
|
||||
slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
|
||||
return slo;
|
||||
}
|
||||
|
||||
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
sso.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR));
|
||||
sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR));
|
||||
sso.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
||||
sso.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
sso.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
sso.setBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||
return sso;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
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(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
|
||||
key.setEncryption(StaxParserUtil.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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.KEY_ELEMENT))
|
||||
break;
|
||||
else
|
||||
throw logger.parserUnknownEndElement(endElementName);
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(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(StaxParserUtil.getElementText(xmlEventReader));
|
||||
} else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
key.setPublicKeyPem(StaxParserUtil.getElementText(xmlEventReader));
|
||||
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
key.setPrivateKeyPem(StaxParserUtil.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(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
|
||||
keyStore.setAlias(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
|
||||
keyStore.setFile(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
|
||||
keyStore.setResource(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
|
||||
if (keyStore.getFile() == null && keyStore.getResource() == null) {
|
||||
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
|
||||
}
|
||||
keyStore.setPassword(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
|
||||
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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
keyStore.setCertificateAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
|
||||
if (keyStore.getCertificateAlias() == null) {
|
||||
throw new ParsingException("KeyStore Certificate element must have the alias attribute set");
|
||||
|
||||
}
|
||||
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
keyStore.setPrivateKeyAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
|
||||
if (keyStore.getPrivateKeyAlias() == null) {
|
||||
throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
|
||||
|
||||
}
|
||||
keyStore.setPrivateKeyPassword(StaxParserUtil.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;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
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.parsers.AbstractParser;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakSamlAdapterXMLParser extends AbstractParser {
|
||||
|
||||
@Override
|
||||
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.getStartElementName(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);
|
||||
}
|
||||
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
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.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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.KEYS_ELEMENT))
|
||||
break;
|
||||
else
|
||||
throw logger.parserUnknownEndElement(endElementName);
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface ResourceLoader {
|
||||
InputStream getResourceAsStream(String resource);
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
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.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.LinkedList;
|
||||
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 {
|
||||
|
||||
@Override
|
||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.SP_ELEMENT);
|
||||
SP sp = new SP();
|
||||
String entityID = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
||||
if (entityID == null) {
|
||||
throw new ParsingException("entityID must be set on SP");
|
||||
|
||||
}
|
||||
sp.setEntityID(entityID);
|
||||
sp.setSslPolicy(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR));
|
||||
sp.setLogoutPage(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR));
|
||||
sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR));
|
||||
sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR));
|
||||
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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.SP_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(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 = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
|
||||
if (policy == null) {
|
||||
throw new ParsingException("PrincipalNameMapping element must have the policy attribute set");
|
||||
|
||||
}
|
||||
String attribute = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
|
||||
SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
|
||||
mapping.setPolicy(policy);
|
||||
mapping.setAttributeName(attribute);
|
||||
sp.setPrincipalNameMapping(mapping);
|
||||
|
||||
} else if (tag.equals(ConfigXmlConstants.ROLE_MAPPING_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_MAPPING_ELEMENT);
|
||||
Set<String> roleAttributes = new HashSet<>();
|
||||
Set<String> roleFriendlyAttributes = 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.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.ROLE_MAPPING_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
|
||||
if (attributeValue == null) {
|
||||
throw new ParsingException("RoleMapping Attribute element must have the name attribute set");
|
||||
|
||||
}
|
||||
roleAttributes.add(attributeValue);
|
||||
} else if (tag.equals(ConfigXmlConstants.FRIENDLY_ATTRIBUTE_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
|
||||
if (attributeValue == null) {
|
||||
throw new ParsingException("RoleMapping FriendlyAttribute element must have the name attribute set");
|
||||
|
||||
}
|
||||
roleFriendlyAttributes.add(attributeValue);
|
||||
} else {
|
||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
||||
}
|
||||
|
||||
}
|
||||
sp.setRoleAttributes(roleAttributes);
|
||||
sp.setRoleFriendlyAttributes(roleFriendlyAttributes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package org.keycloak.test.adapters.saml;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.adapters.saml.config.IDP;
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
|
||||
import org.keycloak.adapters.saml.config.SP;
|
||||
import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterXMLParser;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class XmlParserTest {
|
||||
|
||||
@Test
|
||||
public void testXmlParser() throws Exception {
|
||||
InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
|
||||
Assert.assertNotNull(is);
|
||||
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
|
||||
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
|
||||
Assert.assertNotNull(config);
|
||||
Assert.assertEquals(1, config.getSps().size());
|
||||
SP sp = config.getSps().get(0);
|
||||
Assert.assertEquals("sp", sp.getEntityID());
|
||||
Assert.assertEquals("ssl", sp.getSslPolicy());
|
||||
Assert.assertEquals("format", sp.getNameIDPolicyFormat());
|
||||
Assert.assertTrue(sp.isForceAuthentication());
|
||||
Assert.assertEquals(2, sp.getKeys().size());
|
||||
Key signing = sp.getKeys().get(0);
|
||||
Assert.assertTrue(signing.isSigning());
|
||||
Key.KeyStoreConfig keystore = signing.getKeystore();
|
||||
Assert.assertNotNull(keystore);
|
||||
Assert.assertEquals("file", keystore.getFile());
|
||||
Assert.assertEquals("cp", keystore.getResource());
|
||||
Assert.assertEquals("pw", keystore.getPassword());
|
||||
Assert.assertEquals("private alias", keystore.getPrivateKeyAlias());
|
||||
Assert.assertEquals("private pw", keystore.getPrivateKeyPassword());
|
||||
Assert.assertEquals("cert alias", keystore.getCertificateAlias());
|
||||
Key encryption = sp.getKeys().get(1);
|
||||
Assert.assertTrue(encryption.isEncryption());
|
||||
Assert.assertEquals("private pem", encryption.getPrivateKeyPem());
|
||||
Assert.assertEquals("public pem", encryption.getPublicKeyPem());
|
||||
Assert.assertEquals("policy", sp.getPrincipalNameMapping().getPolicy());
|
||||
Assert.assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName());
|
||||
Assert.assertTrue(sp.getRoleAttributes().size() == 1);
|
||||
Assert.assertTrue(sp.getRoleAttributes().contains("member"));
|
||||
Assert.assertTrue(sp.getRoleFriendlyAttributes().size() == 1);
|
||||
Assert.assertTrue(sp.getRoleFriendlyAttributes().contains("memberOf"));
|
||||
|
||||
IDP idp = sp.getIdp();
|
||||
Assert.assertEquals("idp", idp.getEntityID());
|
||||
Assert.assertTrue(idp.getSingleSignOnService().isSignRequest());
|
||||
Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
|
||||
Assert.assertEquals("canon", idp.getSingleSignOnService().getSignatureCanonicalizationMethod());
|
||||
Assert.assertEquals("post", idp.getSingleSignOnService().getRequestBinding());
|
||||
Assert.assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
|
||||
|
||||
Assert.assertTrue(idp.getSingleLogoutService().isSignRequest());
|
||||
Assert.assertTrue(idp.getSingleLogoutService().isSignResponse());
|
||||
Assert.assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
|
||||
Assert.assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
|
||||
Assert.assertEquals("canon", idp.getSingleLogoutService().getSignatureCanonicalizationMethod());
|
||||
Assert.assertEquals("redirect", idp.getSingleLogoutService().getRequestBinding());
|
||||
Assert.assertEquals("post", idp.getSingleLogoutService().getResponseBinding());
|
||||
Assert.assertEquals("posturl", idp.getSingleLogoutService().getPostBindingUrl());
|
||||
Assert.assertEquals("redirecturl", idp.getSingleLogoutService().getRedirectBindingUrl());
|
||||
|
||||
Assert.assertTrue(idp.getKeys().size() == 1);
|
||||
Assert.assertTrue(idp.getKeys().get(0).isSigning());
|
||||
Assert.assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
61
saml/client-adapter/core/src/test/resources/keycloak-saml.xml
Executable file
61
saml/client-adapter/core/src/test/resources/keycloak-saml.xml
Executable file
|
@ -0,0 +1,61 @@
|
|||
<keycloak-saml-adapter>
|
||||
<SP entityID="sp"
|
||||
sslPolicy="ssl"
|
||||
nameIDPolicyFormat="format"
|
||||
forceAuthentication="true">
|
||||
<Keys>
|
||||
<Key signing="true" >
|
||||
<KeyStore file="file" classpath="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="policy" attribute="attribute"/>
|
||||
<RoleMapping>
|
||||
<Attribute name="member"/>
|
||||
<FriendlyAttribute name="memberOf"/>
|
||||
</RoleMapping>
|
||||
<IDP entityID="idp">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateResponseSignature="true"
|
||||
signatureCanonicalizationMethod="canon"
|
||||
requestBinding="post"
|
||||
bindingUrl="url"
|
||||
/>
|
||||
|
||||
<SingleLogoutService
|
||||
validateRequestSignature="true"
|
||||
validateResponseSignature="true"
|
||||
signRequest="true"
|
||||
signResponse="true"
|
||||
signatureCanonicalizationMethod="canon"
|
||||
requestBinding="redirect"
|
||||
responseBinding="post"
|
||||
postBindingUrl="posturl"
|
||||
redirectBindingUrl="redirecturl"
|
||||
/>
|
||||
<Keys>
|
||||
<Key signing="true">
|
||||
<CertificatePem>
|
||||
cert pem
|
||||
</CertificatePem>
|
||||
</Key>
|
||||
</Keys>
|
||||
</IDP>
|
||||
<Keys>
|
||||
<KeyStore>
|
||||
|
||||
</KeyStore>
|
||||
</Keys>
|
||||
|
||||
</SP>
|
||||
</keycloak-saml-adapter>
|
|
@ -42,16 +42,13 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
public static final AttachmentKey<AuthChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(AuthChallenge.class);
|
||||
protected SamlDeploymentContext deploymentContext;
|
||||
protected UndertowUserSessionManagement sessionManagement;
|
||||
protected String logoutPage;
|
||||
protected String errorPage;
|
||||
|
||||
public AbstractSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement,
|
||||
String logoutPage,
|
||||
String errorPage) {
|
||||
this.deploymentContext = deploymentContext;
|
||||
this.sessionManagement = sessionManagement;
|
||||
this.errorPage = errorPage;
|
||||
this.logoutPage = logoutPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +59,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
Integer code = servePage(exchange, errorPage);
|
||||
return new ChallengeResult(true, code);
|
||||
}
|
||||
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
|
||||
UndertowHttpFacade facade = createFacade(exchange);
|
||||
if (challenge.challenge(facade)) {
|
||||
return new ChallengeResult(true, exchange.getResponseCode());
|
||||
}
|
||||
|
@ -91,7 +88,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
if (notification.getEventType() != SecurityNotification.EventType.LOGGED_OUT) return;
|
||||
|
||||
HttpServerExchange exchange = notification.getExchange();
|
||||
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
|
||||
UndertowHttpFacade facade = createFacade(exchange);
|
||||
SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
SamlSessionStore sessionStore = getTokenStore(exchange, facade, deployment, securityContext);
|
||||
sessionStore.logoutAccount();
|
||||
|
@ -105,7 +102,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
* Call this inside your authenticate method.
|
||||
*/
|
||||
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
|
||||
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
|
||||
UndertowHttpFacade facade = createFacade(exchange);
|
||||
SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (!deployment.isConfigured()) {
|
||||
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
||||
|
@ -120,10 +117,8 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
}
|
||||
if (outcome == AuthOutcome.LOGGED_OUT) {
|
||||
securityContext.logout();
|
||||
if (logoutPage != null) {
|
||||
sendRedirect(exchange, logoutPage);
|
||||
exchange.setResponseCode(302);
|
||||
exchange.endExchange();
|
||||
if (deployment.getLogoutPage() != null) {
|
||||
redirectLogout(deployment, exchange);
|
||||
}
|
||||
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
@ -138,5 +133,16 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
|
|||
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
|
||||
String page = deployment.getLogoutPage();
|
||||
sendRedirect(exchange, page);
|
||||
exchange.setResponseCode(302);
|
||||
exchange.endExchange();
|
||||
}
|
||||
|
||||
protected UndertowHttpFacade createFacade(HttpServerExchange exchange) {
|
||||
return new UndertowHttpFacade(exchange);
|
||||
}
|
||||
|
||||
protected abstract SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext);
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* 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.undertow;
|
||||
|
||||
import io.undertow.security.api.AuthenticationMechanism;
|
||||
import io.undertow.security.api.AuthenticationMechanismFactory;
|
||||
import io.undertow.security.idm.Account;
|
||||
import io.undertow.security.idm.Credential;
|
||||
import io.undertow.security.idm.IdentityManager;
|
||||
import io.undertow.server.handlers.form.FormParserFactory;
|
||||
import io.undertow.servlet.ServletExtension;
|
||||
import io.undertow.servlet.api.AuthMethodConfig;
|
||||
import io.undertow.servlet.api.DeploymentInfo;
|
||||
import io.undertow.servlet.api.LoginConfig;
|
||||
import io.undertow.servlet.api.ServletSessionConfig;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.saml.DefaultSamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlConfigResolver;
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlDeploymentContext;
|
||||
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
|
||||
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
|
||||
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SamlServletExtension implements ServletExtension {
|
||||
|
||||
protected static Logger log = Logger.getLogger(SamlServletExtension.class);
|
||||
|
||||
// todo when this DeploymentInfo method of the same name is fixed.
|
||||
public boolean isAuthenticationMechanismPresent(DeploymentInfo deploymentInfo, final String mechanismName) {
|
||||
LoginConfig loginConfig = deploymentInfo.getLoginConfig();
|
||||
if (loginConfig != null) {
|
||||
for (AuthMethodConfig method : loginConfig.getAuthMethods()) {
|
||||
if (method.getName().equalsIgnoreCase(mechanismName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static InputStream getConfigInputStream(ServletContext context) {
|
||||
InputStream is = null;
|
||||
if (is == null) {
|
||||
String path = context.getInitParameter("keycloak.config.file");
|
||||
if (path == null) {
|
||||
log.debug("using /WEB-INF/keycloak-saml.xml");
|
||||
is = context.getResourceAsStream("/WEB-INF/keycloak-saml.xml");
|
||||
} else {
|
||||
try {
|
||||
is = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UseSpecificCatch")
|
||||
public void handleDeployment(DeploymentInfo deploymentInfo, final ServletContext servletContext) {
|
||||
if (!isAuthenticationMechanismPresent(deploymentInfo, "KEYCLOAK-SAML")) {
|
||||
log.debug("auth-method is not keycloak saml!");
|
||||
return;
|
||||
}
|
||||
log.debug("SamlServletException initialization");
|
||||
|
||||
// Possible scenarios:
|
||||
// 1) The deployment has a keycloak.config.resolver specified and it exists:
|
||||
// Outcome: adapter uses the resolver
|
||||
// 2) The deployment has a keycloak.config.resolver and isn't valid (doesn't exists, isn't a resolver, ...) :
|
||||
// Outcome: adapter is left unconfigured
|
||||
// 3) The deployment doesn't have a keycloak.config.resolver , but has a keycloak.json (or equivalent)
|
||||
// Outcome: adapter uses it
|
||||
// 4) The deployment doesn't have a keycloak.config.resolver nor keycloak.json (or equivalent)
|
||||
// Outcome: adapter is left unconfigured
|
||||
|
||||
SamlConfigResolver configResolver;
|
||||
String configResolverClass = servletContext.getInitParameter("keycloak.config.resolver");
|
||||
SamlDeploymentContext deploymentContext = null;
|
||||
if (configResolverClass != null) {
|
||||
try {
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
//configResolver = (SamlConfigResolver) deploymentInfo.getClassLoader().loadClass(configResolverClass).newInstance();
|
||||
//deploymentContext = new AdapterDeploymentContext(configResolver);
|
||||
//log.info("Using " + configResolverClass + " to resolve Keycloak configuration on a per-request basis.");
|
||||
} catch (Exception ex) {
|
||||
log.warn("The specified resolver " + configResolverClass + " could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: " + ex.getMessage());
|
||||
//deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
} else {
|
||||
InputStream is = getConfigInputStream(servletContext);
|
||||
final SamlDeployment deployment;
|
||||
if (is == null) {
|
||||
log.warn("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
deployment = new DefaultSamlDeployment();
|
||||
} else {
|
||||
try {
|
||||
ResourceLoader loader = new ResourceLoader() {
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resource) {
|
||||
return servletContext.getResourceAsStream(resource);
|
||||
}
|
||||
};
|
||||
deployment = new DeploymentBuilder().build(is, loader);
|
||||
} catch (ParsingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
deploymentContext = new SamlDeploymentContext(deployment);
|
||||
log.debug("Keycloak is using a per-deployment configuration.");
|
||||
}
|
||||
|
||||
servletContext.setAttribute(SamlDeploymentContext.class.getName(), deploymentContext);
|
||||
UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
|
||||
final ServletSamlAuthMech mech = new ServletSamlAuthMech(deploymentContext, userSessionManagement, getErrorPage(deploymentInfo));
|
||||
|
||||
|
||||
// setup handlers
|
||||
|
||||
deploymentInfo.addAuthenticationMechanism("KEYCLOAK-SAML", new AuthenticationMechanismFactory() {
|
||||
@Override
|
||||
public AuthenticationMechanism create(String s, FormParserFactory formParserFactory, Map<String, String> stringStringMap) {
|
||||
return mech;
|
||||
}
|
||||
}); // authentication
|
||||
|
||||
deploymentInfo.setIdentityManager(new IdentityManager() {
|
||||
@Override
|
||||
public Account verify(Account account) {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(String id, Credential credential) {
|
||||
throw new IllegalStateException("Should never be called in Keycloak flow");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(Credential credential) {
|
||||
throw new IllegalStateException("Should never be called in Keycloak flow");
|
||||
}
|
||||
});
|
||||
|
||||
log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
|
||||
ServletSessionConfig cookieConfig = new ServletSessionConfig();
|
||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||
|
||||
}
|
||||
|
||||
protected String getErrorPage(DeploymentInfo deploymentInfo) {
|
||||
LoginConfig loginConfig = deploymentInfo.getLoginConfig();
|
||||
String errorPage = null;
|
||||
if (loginConfig != null) {
|
||||
errorPage = loginConfig.getErrorPage();
|
||||
}
|
||||
return errorPage;
|
||||
}
|
||||
}
|
|
@ -2,24 +2,67 @@ package org.keycloak.adapters.saml.undertow;
|
|||
|
||||
import io.undertow.security.api.SecurityContext;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.servlet.handlers.ServletRequestContext;
|
||||
import io.undertow.util.Headers;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlDeploymentContext;
|
||||
import org.keycloak.adapters.saml.SamlSessionStore;
|
||||
import org.keycloak.adapters.undertow.ServletHttpFacade;
|
||||
import org.keycloak.adapters.undertow.UndertowHttpFacade;
|
||||
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ServletSamlAuthMech extends AbstractSamlAuthMech {
|
||||
public ServletSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement,
|
||||
String logoutPage, String errorPage) {
|
||||
super(deploymentContext, sessionManagement, logoutPage, errorPage);
|
||||
public ServletSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement, String errorPage) {
|
||||
super(deploymentContext, sessionManagement, errorPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext) {
|
||||
return new ServletSamlSessionStore(exchange, sessionManagement, securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UndertowHttpFacade createFacade(HttpServerExchange exchange) {
|
||||
return new ServletHttpFacade(exchange);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
|
||||
servePage(exchange, deployment.getLogoutPage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer servePage(HttpServerExchange exchange, String location) {
|
||||
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
|
||||
ServletRequest req = servletRequestContext.getServletRequest();
|
||||
ServletResponse resp = servletRequestContext.getServletResponse();
|
||||
RequestDispatcher disp = req.getRequestDispatcher(location);
|
||||
//make sure the login page is never cached
|
||||
exchange.getResponseHeaders().add(Headers.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
|
||||
exchange.getResponseHeaders().add(Headers.PRAGMA, "no-cache");
|
||||
exchange.getResponseHeaders().add(Headers.EXPIRES, "0");
|
||||
|
||||
|
||||
try {
|
||||
disp.forward(req, resp);
|
||||
} catch (ServletException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -104,6 +104,23 @@ public class StaxParserUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Attribute value
|
||||
*
|
||||
* @param startElement
|
||||
* @param tag localpart of the qname of the attribute
|
||||
*
|
||||
* @return false if attribute not set
|
||||
*/
|
||||
public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
|
||||
String result = null;
|
||||
Attribute attr = startElement.getAttributeByName(new QName(tag));
|
||||
if (attr != null)
|
||||
result = getAttributeValue(attr);
|
||||
if (result == null) return false;
|
||||
return Boolean.valueOf(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given that the {@code XMLEventReader} is in {@code XMLStreamConstants.START_ELEMENT} mode, we parse into a DOM
|
||||
* Element
|
||||
|
|
|
@ -101,6 +101,14 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-adapter-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-saml-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
|
||||
|
|
|
@ -0,0 +1,510 @@
|
|||
package org.keycloak.testsuite.keycloaksaml;
|
||||
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
|
||||
import org.keycloak.protocol.saml.mappers.HardcodedRole;
|
||||
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
||||
import org.keycloak.protocol.saml.mappers.RoleNameMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
|
||||
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
||||
import org.keycloak.saml.processing.web.util.PostBindingUtil;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.ClientRequestContext;
|
||||
import javax.ws.rs.client.ClientRequestFilter;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SamlBindingTest {
|
||||
|
||||
@ClassRule
|
||||
public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
|
||||
@Override
|
||||
public void initWars() {
|
||||
ClassLoader classLoader = SamlBindingTest.class.getClassLoader();
|
||||
|
||||
//initializeSamlSecuredWar("/keycloak-saml/simple-post", "/sales-post", "post.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-get", "/employee-sig", "employee-sig.war", classLoader);
|
||||
//initializeSamlSecuredWar("/saml/simple-get", "/employee", "employee.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
|
||||
//initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
||||
//uploadSP();
|
||||
//server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmJson() {
|
||||
return "/saml/testsaml.json";
|
||||
}
|
||||
};
|
||||
|
||||
public static class SamlSPFacade extends HttpServlet {
|
||||
public static String samlResponse;
|
||||
public static String RELAY_STATE = "http://test.com/foo/bar";
|
||||
public static String sentRelayState;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handler(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handler(req, resp);
|
||||
}
|
||||
|
||||
private void handler(HttpServletRequest req, HttpServletResponse resp) {
|
||||
System.out.println("********* HERE ******");
|
||||
if (req.getParameterMap().isEmpty()) {
|
||||
System.out.println("redirecting");
|
||||
resp.setStatus(302);
|
||||
// Redirect
|
||||
// UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D");
|
||||
UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
|
||||
builder.queryParam("RelayState", RELAY_STATE);
|
||||
resp.setHeader("Location", builder.build().toString());
|
||||
return;
|
||||
}
|
||||
System.out.println("received response");
|
||||
samlResponse = req.getParameter("SAMLResponse");
|
||||
sentRelayState = req.getParameter("RelayState");
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
@WebResource
|
||||
protected WebDriver driver;
|
||||
@WebResource
|
||||
protected LoginPage loginPage;
|
||||
|
||||
protected void checkLoggedOut(String mainUrl) {
|
||||
String pageSource = driver.getPageSource();
|
||||
System.out.println("*** logout pagesource ***");
|
||||
System.out.println(pageSource);
|
||||
System.out.println("driver url: " + driver.getCurrentUrl());
|
||||
Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
|
||||
driver.navigate().to(mainUrl);
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void ideTesting() throws Exception {
|
||||
Thread.sleep(100000000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSimpleLoginLogout() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post/");
|
||||
}
|
||||
@Test
|
||||
public void testPostSimpleLoginLogoutIdpInitiated() {
|
||||
driver.navigate().to("http://localhost:8081/auth/realms/demo/protocol/saml/clients/sales-post");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedLoginLogout() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post-sig/");
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutTransientNameID() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-transient/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertFalse(driver.getPageSource().contains("bburke"));
|
||||
Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post-sig-transient/");
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutPersistentNameID() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertFalse(driver.getPageSource().contains("bburke"));
|
||||
Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/");
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutEmailNameID() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-email/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/");
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post-sig-email/");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelayStateEncoding() throws Exception {
|
||||
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
|
||||
// at the relay state
|
||||
SamlSPFacade.samlResponse = null;
|
||||
driver.navigate().to("http://localhost:8081/employee/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
System.out.println(driver.getCurrentUrl());
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
|
||||
Assert.assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE);
|
||||
Assert.assertNotNull(SamlSPFacade.samlResponse);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAttributes() throws Exception {
|
||||
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
|
||||
// at the assertions sent. This is because Picketlink, AFAICT, does not give you any way to get access to
|
||||
// the assertion.
|
||||
|
||||
{
|
||||
SamlSPFacade.samlResponse = null;
|
||||
driver.navigate().to("http://localhost:8081/employee/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
System.out.println(driver.getCurrentUrl());
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
|
||||
Assert.assertNotNull(SamlSPFacade.samlResponse);
|
||||
SAML2Response saml2Response = new SAML2Response();
|
||||
byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
|
||||
ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
|
||||
Assert.assertTrue(rt.getAssertions().size() == 1);
|
||||
AssertionType assertion = rt.getAssertions().get(0).getAssertion();
|
||||
|
||||
// test attributes and roles
|
||||
|
||||
boolean email = false;
|
||||
boolean phone = false;
|
||||
boolean userRole = false;
|
||||
boolean managerRole = false;
|
||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) {
|
||||
Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName());
|
||||
Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat());
|
||||
Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com");
|
||||
email = true;
|
||||
} else if (attr.getName().equals("phone")) {
|
||||
Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
|
||||
Assert.assertEquals(attr.getAttributeValue().get(0), "617");
|
||||
phone = true;
|
||||
} else if (attr.getName().equals("Role")) {
|
||||
if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
|
||||
if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Assert.assertTrue(email);
|
||||
Assert.assertTrue(phone);
|
||||
Assert.assertTrue(userRole);
|
||||
Assert.assertTrue(managerRole);
|
||||
}
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ClientModel app = appRealm.getClientByClientId("http://localhost:8081/employee/");
|
||||
for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
|
||||
if (mapper.getName().equals("role-list")) {
|
||||
app.removeProtocolMapper(mapper);
|
||||
mapper.setId(null);
|
||||
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
|
||||
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
|
||||
app.addProtocolMapper(mapper);
|
||||
}
|
||||
}
|
||||
app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
|
||||
app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
|
||||
app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
|
||||
app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
|
||||
}
|
||||
}, "demo");
|
||||
|
||||
System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
|
||||
|
||||
{
|
||||
SamlSPFacade.samlResponse = null;
|
||||
driver.navigate().to("http://localhost:8081/employee/");
|
||||
System.out.println(driver.getCurrentUrl());
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
|
||||
Assert.assertNotNull(SamlSPFacade.samlResponse);
|
||||
SAML2Response saml2Response = new SAML2Response();
|
||||
byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
|
||||
ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
|
||||
Assert.assertTrue(rt.getAssertions().size() == 1);
|
||||
AssertionType assertion = rt.getAssertions().get(0).getAssertion();
|
||||
|
||||
// test attributes and roles
|
||||
|
||||
boolean userRole = false;
|
||||
boolean managerRole = false;
|
||||
boolean single = false;
|
||||
boolean hardcodedRole = false;
|
||||
boolean hardcodedAttribute = false;
|
||||
boolean peeOn = false;
|
||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
if (attr.getName().equals("memberOf")) {
|
||||
if (single) Assert.fail("too many role attributes");
|
||||
single = true;
|
||||
for (Object value : attr.getAttributeValue()) {
|
||||
if (value.equals("el-jefe")) managerRole = true;
|
||||
if (value.equals("user")) userRole = true;
|
||||
if (value.equals("hardcoded-role")) hardcodedRole = true;
|
||||
if (value.equals("pee-on")) peeOn = true;
|
||||
}
|
||||
} else if (attr.getName().equals("hardcoded-attribute")) {
|
||||
hardcodedAttribute = true;
|
||||
Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Assert.assertTrue(single);
|
||||
Assert.assertTrue(hardcodedAttribute);
|
||||
Assert.assertTrue(hardcodedRole);
|
||||
Assert.assertTrue(peeOn);
|
||||
Assert.assertTrue(userRole);
|
||||
Assert.assertTrue(managerRole);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogout() {
|
||||
driver.navigate().to("http://localhost:8081/employee-sig/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/employee-sig/");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogoutFrontNoSSO() {
|
||||
driver.navigate().to("http://localhost:8081/employee-sig-front/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/employee-sig-front/");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogoutFront() {
|
||||
// visit 1st app an logg in
|
||||
System.out.println("visit 1st app ");
|
||||
driver.navigate().to("http://localhost:8081/employee-sig/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
System.out.println("login to form");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
|
||||
// visit 2nd app
|
||||
System.out.println("visit 2nd app ");
|
||||
driver.navigate().to("http://localhost:8081/employee-sig-front/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
|
||||
// visit 3rd app
|
||||
System.out.println("visit 3rd app ");
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
|
||||
// logout of first app
|
||||
System.out.println("GLO");
|
||||
driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/employee-sig/");
|
||||
driver.navigate().to("http://localhost:8081/employee-sig-front/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-sig/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostEncryptedLoginLogout() {
|
||||
driver.navigate().to("http://localhost:8081/sales-post-enc/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-post-enc/");
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testPostBadClientSignature() {
|
||||
driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
Assert.assertEquals(driver.getTitle(), "We're sorry...");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostBadRealmSignature() {
|
||||
driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
|
||||
Assert.assertTrue(driver.getPageSource().contains("null"));
|
||||
}
|
||||
|
||||
private static String createToken() {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
try {
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
||||
RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
|
||||
ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
|
||||
TokenManager tm = new TokenManager();
|
||||
UserModel admin = session.users().getUserByUsername("admin", adminRealm);
|
||||
ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
|
||||
clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
|
||||
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
|
||||
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
|
||||
return tm.encodeToken(adminRealm, token);
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMetadataPostSignedLoginLogout() throws Exception {
|
||||
|
||||
driver.navigate().to("http://localhost:8081/sales-metadata/");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||
loginPage.login("bburke", "password");
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
|
||||
String pageSource = driver.getPageSource();
|
||||
Assert.assertTrue(pageSource.contains("bburke"));
|
||||
driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
|
||||
checkLoggedOut("http://localhost:8081/sales-metadata/");
|
||||
|
||||
}
|
||||
|
||||
public static void uploadSP() {
|
||||
String token = createToken();
|
||||
final String authHeader = "Bearer " + token;
|
||||
ClientRequestFilter authFilter = new ClientRequestFilter() {
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
||||
}
|
||||
};
|
||||
Client client = ClientBuilder.newBuilder().register(authFilter).build();
|
||||
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
|
||||
WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
|
||||
|
||||
|
||||
MultipartFormDataOutput formData = new MultipartFormDataOutput();
|
||||
InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
|
||||
Assert.assertNotNull(is);
|
||||
formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
|
||||
|
||||
WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload");
|
||||
System.out.println(upload.getUri());
|
||||
Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
|
||||
Assert.assertEquals(204, response.getStatus());
|
||||
response.close();
|
||||
client.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package org.keycloak.testsuite.keycloaksaml;
|
||||
|
||||
import io.undertow.security.idm.Account;
|
||||
import io.undertow.security.idm.Credential;
|
||||
import io.undertow.security.idm.IdentityManager;
|
||||
import io.undertow.server.handlers.resource.Resource;
|
||||
import io.undertow.server.handlers.resource.ResourceChangeListener;
|
||||
import io.undertow.server.handlers.resource.ResourceManager;
|
||||
import io.undertow.server.handlers.resource.URLResource;
|
||||
import io.undertow.servlet.api.DeploymentInfo;
|
||||
import io.undertow.servlet.api.LoginConfig;
|
||||
import io.undertow.servlet.api.SecurityConstraint;
|
||||
import io.undertow.servlet.api.ServletInfo;
|
||||
import io.undertow.servlet.api.WebResourceCollection;
|
||||
import org.keycloak.adapters.saml.undertow.SamlServletExtension;
|
||||
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
|
||||
import org.picketlink.identity.federation.bindings.wildfly.sp.SPServletExtension;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class SamlKeycloakRule extends AbstractKeycloakRule {
|
||||
|
||||
public static class SendUsernameServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
OutputStream stream = resp.getOutputStream();
|
||||
Principal principal = req.getUserPrincipal();
|
||||
stream.write("request-path: ".getBytes());
|
||||
stream.write(req.getPathInfo().getBytes());
|
||||
stream.write("\n".getBytes());
|
||||
stream.write("principal=".getBytes());
|
||||
if (principal == null) {
|
||||
stream.write("null".getBytes());
|
||||
return;
|
||||
}
|
||||
String name = principal.getName();
|
||||
stream.write(name.getBytes());
|
||||
}
|
||||
@Override
|
||||
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
OutputStream stream = resp.getOutputStream();
|
||||
Principal principal = req.getUserPrincipal();
|
||||
stream.write("request-path: ".getBytes());
|
||||
stream.write(req.getPathInfo().getBytes());
|
||||
stream.write("\n".getBytes());
|
||||
stream.write("principal=".getBytes());
|
||||
if (principal == null) {
|
||||
stream.write("null".getBytes());
|
||||
return;
|
||||
}
|
||||
String name = principal.getName();
|
||||
stream.write(name.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestResourceManager implements ResourceManager {
|
||||
|
||||
private final String basePath;
|
||||
|
||||
public TestResourceManager(String basePath){
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String path) throws IOException {
|
||||
String temp = path;
|
||||
String fullPath = basePath + temp;
|
||||
URL url = getClass().getResource(fullPath);
|
||||
if (url == null) {
|
||||
System.out.println("url is null: " + fullPath);
|
||||
}
|
||||
return new URLResource(url, url.openConnection(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResourceChangeListenerSupported() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerResourceChangeListener(ResourceChangeListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeResourceChangeListener(ResourceChangeListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestIdentityManager implements IdentityManager {
|
||||
@Override
|
||||
public Account verify(Account account) {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(String userName, Credential credential) {
|
||||
throw new RuntimeException("WTF");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(Credential credential) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupKeycloak() {
|
||||
String realmJson = getRealmJson();
|
||||
server.importRealm(getClass().getResourceAsStream(realmJson));
|
||||
initWars();
|
||||
}
|
||||
|
||||
public abstract void initWars();
|
||||
|
||||
public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader) {
|
||||
|
||||
ServletInfo regularServletInfo = new ServletInfo("servlet", SendUsernameServlet.class)
|
||||
.addMapping("/*");
|
||||
|
||||
SecurityConstraint constraint = new SecurityConstraint();
|
||||
WebResourceCollection collection = new WebResourceCollection();
|
||||
collection.addUrlPattern("/*");
|
||||
constraint.addWebResourceCollection(collection);
|
||||
constraint.addRoleAllowed("manager");
|
||||
LoginConfig loginConfig = new LoginConfig("KEYCLOAK-SAML", "Test Realm");
|
||||
|
||||
ResourceManager resourceManager = new TestResourceManager(warResourcePath);
|
||||
|
||||
DeploymentInfo deploymentInfo = new DeploymentInfo()
|
||||
.setClassLoader(classLoader)
|
||||
.setIdentityManager(new TestIdentityManager())
|
||||
.setContextPath(contextPath)
|
||||
.setDeploymentName(warDeploymentName)
|
||||
.setLoginConfig(loginConfig)
|
||||
.setResourceManager(resourceManager)
|
||||
.addServlets(regularServletInfo)
|
||||
.addSecurityConstraint(constraint)
|
||||
.addServletExtension(new SamlServletExtension());
|
||||
server.getServer().deploy(deploymentInfo);
|
||||
}
|
||||
|
||||
public String getRealmJson() {
|
||||
return "/keycloak-saml/testsaml.json";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<keycloak-saml-adapter>
|
||||
<SP entityID="http://localhost:8081/sales-post-sig/"
|
||||
sslPolicy="EXTERNAL"
|
||||
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||
logoutPage="/logout.jsp"
|
||||
forceAuthentication="false">
|
||||
<Keys>
|
||||
<Key signing="true" >
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
|
||||
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
<PrincipalNameMapping policy="FROM_NAME_ID"/>
|
||||
<RoleMapping>
|
||||
<Attribute name="Role"/>
|
||||
</RoleMapping>
|
||||
<IDP entityID="idp">
|
||||
<SingleSignOnService signRequest="true"
|
||||
validateResponseSignature="true"
|
||||
requestBinding="POST"
|
||||
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
|
||||
<SingleLogoutService
|
||||
validateRequestSignature="true"
|
||||
validateResponseSignature="true"
|
||||
signRequest="true"
|
||||
signResponse="true"
|
||||
requestBinding="POST"
|
||||
responseBinding="POST"
|
||||
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
|
||||
/>
|
||||
<Keys>
|
||||
<Key signing="true">
|
||||
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
|
||||
<Certificate alias="demo"/>
|
||||
</KeyStore>
|
||||
</Key>
|
||||
</Keys>
|
||||
</IDP>
|
||||
</SP>
|
||||
</keycloak-saml-adapter>
|
Binary file not shown.
310
testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
Executable file
310
testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
Executable file
|
@ -0,0 +1,310 @@
|
|||
{
|
||||
"id": "demo",
|
||||
"realm": "demo",
|
||||
"enabled": true,
|
||||
"sslRequired": "external",
|
||||
"registrationAllowed": true,
|
||||
"resetPasswordAllowed": true,
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [ "password" ],
|
||||
"defaultRoles": [ "user" ],
|
||||
"smtpServer": {
|
||||
"from": "auto@keycloak.org",
|
||||
"host": "localhost",
|
||||
"port":"3025"
|
||||
},
|
||||
"users" : [
|
||||
{
|
||||
"username" : "bburke",
|
||||
"enabled": true,
|
||||
"email" : "bburke@redhat.com",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
],
|
||||
"attributes" : {
|
||||
"phone": "617"
|
||||
},
|
||||
"realmRoles": ["manager", "user"],
|
||||
"applicationRoles": {
|
||||
"http://localhost:8081/employee/": [ "employee" ]
|
||||
}
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post/",
|
||||
"enabled": true,
|
||||
"fullScopeAllowed": true,
|
||||
"protocol": "saml",
|
||||
"baseUrl": "http://localhost:8081/sales-post",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.authnstatement": "true",
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post/",
|
||||
"saml_idp_initiated_sso_url_name": "sales-post"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-sig",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-sig-transient",
|
||||
"adminUrl": "http://localhost:8081/sales-post-sig-transient",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-sig-transient/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-sig-persistent/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-sig-persistent",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-sig-persistent/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-persistent/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-persistent/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-sig-email/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-sig-email",
|
||||
"adminUrl": "http://localhost:8081/sales-post-sig-email",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-sig-email/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_force_name_id_format": "true",
|
||||
"saml_name_id_format": "email",
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-email/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-email/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-email/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-email/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/bad-realm-sales-post-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
|
||||
"adminUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/bad-realm-sales-post-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/bad-client-sales-post-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/bad-client-sales-post-sig/",
|
||||
"adminUrl": "http://localhost:8081/bad-client-sales-post-sig/",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/bad-client-sales-post-sig/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/sales-post-enc/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/sales-post-enc",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/sales-post-enc/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-enc/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-enc/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA512",
|
||||
"saml.client.signature": "true",
|
||||
"saml.encrypt": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
|
||||
"saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/employee-sig/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/employee-sig",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/employee-sig/*"
|
||||
],
|
||||
"adminUrl": "http://localhost:8081/employee-sig/",
|
||||
"attributes": {
|
||||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA1",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/employee/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"baseUrl": "http://localhost:8081/employee",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/employee/*"
|
||||
],
|
||||
"adminUrl": "http://localhost:8081/employee/",
|
||||
"attributes": {
|
||||
"saml.authnstatement": "true"
|
||||
},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "email",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "email",
|
||||
"friendly.name": "email",
|
||||
"attribute.name": "urn:oid:1.2.840.113549.1.9.1",
|
||||
"attribute.nameformat": "URI Reference"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "phone",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-attribute-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "phone",
|
||||
"attribute.name": "phone",
|
||||
"attribute.nameformat": "Basic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "role-list",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-role-list-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"attribute.name": "Role",
|
||||
"attribute.nameformat": "Basic",
|
||||
"single": "false"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "http://localhost:8081/employee-sig-front/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"frontchannelLogout": true,
|
||||
"baseUrl": "http://localhost:8081/employee-sig-front/",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/employee-sig-front/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/employee-sig-front/",
|
||||
"saml_assertion_consumer_url_redirect": "http://localhost:8081/employee-sig-front/",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/employee-sig-front/",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:8081/employee-sig-front/",
|
||||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA1",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
||||
}
|
||||
}
|
||||
],
|
||||
"roles" : {
|
||||
"realm" : [
|
||||
{
|
||||
"name": "manager",
|
||||
"description": "Have Manager privileges"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"description": "Have User privileges"
|
||||
}
|
||||
],
|
||||
"application" : {
|
||||
"http://localhost:8081/employee/" : [
|
||||
{
|
||||
"name": "employee",
|
||||
"description": "Have Employee privileges"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,7 +69,6 @@
|
|||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
|
@ -92,7 +91,6 @@
|
|||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
|
@ -114,7 +112,6 @@
|
|||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
|
@ -139,7 +136,6 @@
|
|||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
|
@ -157,7 +153,6 @@
|
|||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||
}
|
||||
},
|
||||
|
@ -175,7 +170,6 @@
|
|||
"saml.server.signature": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||
}
|
||||
},
|
||||
|
@ -198,9 +192,7 @@
|
|||
"saml.client.signature": "true",
|
||||
"saml.encrypt": "true",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
|
||||
"saml.encryption.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||
"saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||
}
|
||||
},
|
||||
|
@ -219,7 +211,6 @@
|
|||
"saml.client.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA1",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
|
||||
"saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
||||
}
|
||||
},
|
||||
|
@ -292,7 +283,6 @@
|
|||
"saml.client.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA1",
|
||||
"saml.authnstatement": "true",
|
||||
"saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
|
||||
"saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue