keycloak-aplcache

set framework for template config

1/4/2016 8:13:15 PM

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientTemplateRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientTemplateRepresentation.java
index dc575c4..e478c27 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientTemplateRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientTemplateRepresentation.java
@@ -17,6 +17,16 @@ public class ClientTemplateRepresentation {
     protected String description;
     protected String protocol;
     protected Boolean fullScopeAllowed;
+    protected Boolean bearerOnly;
+    protected Boolean consentRequired;
+    protected Boolean standardFlowEnabled;
+    protected Boolean implicitFlowEnabled;
+    protected Boolean directAccessGrantsEnabled;
+    protected Boolean serviceAccountsEnabled;
+    protected Boolean publicClient;
+    protected Boolean frontchannelLogout;
+    protected Map<String, String> attributes;
+
     protected List<ProtocolMapperRepresentation> protocolMappers;
 
     public String getId() {
@@ -67,4 +77,76 @@ public class ClientTemplateRepresentation {
     public void setFullScopeAllowed(Boolean fullScopeAllowed) {
         this.fullScopeAllowed = fullScopeAllowed;
     }
+
+    public Boolean isBearerOnly() {
+        return bearerOnly;
+    }
+
+    public void setBearerOnly(Boolean bearerOnly) {
+        this.bearerOnly = bearerOnly;
+    }
+
+    public Boolean isConsentRequired() {
+        return consentRequired;
+    }
+
+    public void setConsentRequired(Boolean consentRequired) {
+        this.consentRequired = consentRequired;
+    }
+
+    public Boolean isStandardFlowEnabled() {
+        return standardFlowEnabled;
+    }
+
+    public void setStandardFlowEnabled(Boolean standardFlowEnabled) {
+        this.standardFlowEnabled = standardFlowEnabled;
+    }
+
+    public Boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabled;
+    }
+
+    public void setImplicitFlowEnabled(Boolean implicitFlowEnabled) {
+        this.implicitFlowEnabled = implicitFlowEnabled;
+    }
+
+    public Boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabled;
+    }
+
+    public void setDirectAccessGrantsEnabled(Boolean directAccessGrantsEnabled) {
+        this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+    }
+
+    public Boolean isServiceAccountsEnabled() {
+        return serviceAccountsEnabled;
+    }
+
+    public void setServiceAccountsEnabled(Boolean serviceAccountsEnabled) {
+        this.serviceAccountsEnabled = serviceAccountsEnabled;
+    }
+
+    public Boolean isPublicClient() {
+        return publicClient;
+    }
+
+    public void setPublicClient(Boolean publicClient) {
+        this.publicClient = publicClient;
+    }
+
+    public Boolean isFrontchannelLogout() {
+        return frontchannelLogout;
+    }
+
+    public void setFrontchannelLogout(Boolean frontchannelLogout) {
+        this.frontchannelLogout = frontchannelLogout;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, String> attributes) {
+        this.attributes = attributes;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/ClientConfigResolver.java b/model/api/src/main/java/org/keycloak/models/ClientConfigResolver.java
new file mode 100755
index 0000000..8ec8728
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/ClientConfigResolver.java
@@ -0,0 +1,55 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClientConfigResolver {
+    protected ClientModel client;
+    protected ClientTemplateModel clientTemplate;
+
+    public ClientConfigResolver(ClientModel client) {
+        this.client = client;
+        this.clientTemplate = client.getClientTemplate();
+    }
+
+    public String resolveAttribute(String name) {
+        if (clientTemplate != null && client.useTemplateConfig()) {
+            return clientTemplate.getAttribute(name);
+        } else {
+            return client.getAttribute(name);
+        }
+    }
+
+    public boolean isFrontchannelLogout() {
+        if (clientTemplate != null && client.useTemplateConfig()) {
+            return clientTemplate.isFrontchannelLogout();
+        }
+
+        return client.isFrontchannelLogout();
+    }
+
+    boolean isConsentRequired() {
+        if (clientTemplate != null && client.useTemplateConfig()) {
+            return clientTemplate.isConsentRequired();
+        }
+
+        return client.isConsentRequired();
+    }
+
+    boolean isStandardFlowEnabled() {
+        if (clientTemplate != null && client.useTemplateConfig()) {
+            return clientTemplate.isStandardFlowEnabled();
+        }
+
+        return client.isStandardFlowEnabled();
+    }
+
+    boolean isServiceAccountsEnabled() {
+        if (clientTemplate != null && client.useTemplateConfig()) {
+            return clientTemplate.isServiceAccountsEnabled();
+        }
+
+        return client.isServiceAccountsEnabled();
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 2432fc1..3b2cfdc 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -903,7 +903,7 @@ public class RepresentationToModel {
             }
         }
         if (resourceRep.isUseTemplateConfig() != null) client.setUseTemplateConfig(resourceRep.isUseTemplateConfig());
-        else client.setUseTemplateConfig(resourceRep.getClientTemplate() != null);
+        else client.setUseTemplateConfig(false); // default to false for now
 
         if (resourceRep.isUseTemplateScope() != null) client.setUseTemplateScope(resourceRep.isUseTemplateScope());
         else client.setUseTemplateScope(resourceRep.getClientTemplate() != null);
@@ -1022,6 +1022,23 @@ public class RepresentationToModel {
                 client.addProtocolMapper(toModel(mapper));
             }
         }
+        if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly());
+        if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired());
+
+        if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
+        if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
+        if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
+        if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
+
+        if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
+        if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
+
+        if (resourceRep.getAttributes() != null) {
+            for (Map.Entry<String, String> entry : resourceRep.getAttributes().entrySet()) {
+                client.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
+
 
         return client;
     }
@@ -1035,6 +1052,23 @@ public class RepresentationToModel {
 
 
         if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
+
+        if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
+        if (rep.isConsentRequired() != null) resource.setConsentRequired(rep.isConsentRequired());
+        if (rep.isStandardFlowEnabled() != null) resource.setStandardFlowEnabled(rep.isStandardFlowEnabled());
+        if (rep.isImplicitFlowEnabled() != null) resource.setImplicitFlowEnabled(rep.isImplicitFlowEnabled());
+        if (rep.isDirectAccessGrantsEnabled() != null) resource.setDirectAccessGrantsEnabled(rep.isDirectAccessGrantsEnabled());
+        if (rep.isServiceAccountsEnabled() != null) resource.setServiceAccountsEnabled(rep.isServiceAccountsEnabled());
+        if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
+        if (rep.isFullScopeAllowed() != null) resource.setFullScopeAllowed(rep.isFullScopeAllowed());
+        if (rep.isFrontchannelLogout() != null) resource.setFrontchannelLogout(rep.isFrontchannelLogout());
+
+        if (rep.getAttributes() != null) {
+            for (Map.Entry<String, String> entry : rep.getAttributes().entrySet()) {
+                resource.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
+
     }
 
     public static long getClaimsMask(ClaimRepresentation rep) {
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
old mode 100644
new mode 100755
index 52b8557..f262346
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
@@ -9,6 +9,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.DefaultAuthenticationFlows;
 import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
+import org.keycloak.protocol.saml.SamlConfigAttributes;
 import org.keycloak.protocol.saml.SamlProtocol;
 import org.keycloak.protocol.saml.SamlService;
 import org.keycloak.protocol.saml.profile.ecp.util.Soap;
@@ -99,7 +100,7 @@ public class SamlEcpProfileService extends SamlService {
             private void createRequestAuthenticatedHeader(ClientSessionModel clientSession, Soap.SoapMessageBuilder messageBuilder) {
                 ClientModel client = clientSession.getClient();
 
-                if ("true".equals(client.getAttribute(SamlProtocol.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
+                if ("true".equals(client.getAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
                     SOAPHeaderElement ecpRequestAuthenticated = messageBuilder.addHeader(JBossSAMLConstants.REQUEST_AUTHENTICATED.get(), NS_PREFIX_PROFILE_ECP);
 
                     ecpRequestAuthenticated.setMustUnderstand(true);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
index df27de2..d935f83 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
@@ -1,5 +1,6 @@
 package org.keycloak.protocol.saml;
 
+import org.keycloak.models.ClientConfigResolver;
 import org.keycloak.models.ClientModel;
 import org.keycloak.saml.SignatureAlgorithm;
 
@@ -7,24 +8,14 @@ import org.keycloak.saml.SignatureAlgorithm;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class SamlClient {
-    protected ClientModel client;
+public class SamlClient extends ClientConfigResolver {
 
     public SamlClient(ClientModel client) {
-        this.client = client;
+        super(client);
     }
 
-    public String getId() {
-        return client.getId();
-    }
-
-    public String getClientId() {
-        return client.getClientId();
-    }
-//
-
     public String getCanonicalizationMethod() {
-        return client.getAttribute(SamlConfigAttributes.SAML_CANONICALIZATION_METHOD_ATTRIBUTE);
+        return resolveAttribute(SamlConfigAttributes.SAML_CANONICALIZATION_METHOD_ATTRIBUTE);
     }
 
     public void setCanonicalizationMethod(String value) {
@@ -32,7 +23,7 @@ public class SamlClient {
     }
 
     public SignatureAlgorithm getSignatureAlgorithm() {
-        String alg = client.getAttribute(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM);
+        String alg = resolveAttribute(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM);
         if (alg != null) {
             SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(alg);
             if (algorithm != null)
@@ -46,14 +37,14 @@ public class SamlClient {
     }
 
     public String getNameIDFormat() {
-        return client.getAttributes().get(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE);
+        return resolveAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE);
     }
     public void setNameIDFormat(String format) {
         client.setAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE, format);
     }
 
     public boolean includeAuthnStatement() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT));
+        return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT));
     }
 
     public void setIncludeAuthnStatement(boolean val) {
@@ -61,7 +52,7 @@ public class SamlClient {
     }
 
     public boolean forceNameIDFormat() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE));
+        return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE));
 
     }
     public void setForceNameIDFormat(boolean val) {
@@ -69,7 +60,7 @@ public class SamlClient {
     }
 
     public boolean requiresRealmSignature() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE));
+        return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE));
     }
 
     public void setRequiresRealmSignature(boolean val) {
@@ -78,7 +69,7 @@ public class SamlClient {
     }
 
     public boolean forcePostBinding() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_FORCE_POST_BINDING));
+        return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_FORCE_POST_BINDING));
     }
 
     public void setForcePostBinding(boolean val) {
@@ -86,7 +77,7 @@ public class SamlClient {
 
     }
     public boolean requiresAssertionSignature() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE));
+       return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE));
     }
 
     public void setRequiresAssertionSignature(boolean val) {
@@ -94,7 +85,7 @@ public class SamlClient {
 
     }
     public boolean requiresEncryption() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_ENCRYPT));
+       return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_ENCRYPT));
     }
 
 
@@ -104,7 +95,7 @@ public class SamlClient {
     }
 
     public boolean requiresClientSignature() {
-        return "true".equals(client.getAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE));
+        return "true".equals(resolveAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE));
     }
 
     public void setRequiresClientSignature(boolean val) {
@@ -129,4 +120,5 @@ public class SamlClient {
         client.setAttribute(SamlConfigAttributes.SAML_SIGNING_PRIVATE_KEY, val);
 
     }
+
 }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClientTemplate.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClientTemplate.java
new file mode 100755
index 0000000..ae6d491
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClientTemplate.java
@@ -0,0 +1,131 @@
+package org.keycloak.protocol.saml;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.saml.SignatureAlgorithm;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlClientTemplate {
+    protected ClientTemplateModel clientTemplate;
+
+    public SamlClientTemplate(ClientTemplateModel template) {
+        this.clientTemplate = template;
+    }
+
+    public String getId() {
+        return clientTemplate.getId();
+    }
+
+//
+
+    public String getCanonicalizationMethod() {
+        return clientTemplate.getAttribute(SamlConfigAttributes.SAML_CANONICALIZATION_METHOD_ATTRIBUTE);
+    }
+
+    public void setCanonicalizationMethod(String value) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_CANONICALIZATION_METHOD_ATTRIBUTE, value);
+    }
+
+    public SignatureAlgorithm getSignatureAlgorithm() {
+        String alg = null;
+        alg = clientTemplate.getAttribute(SamlConfigAttributes.SAML_CANONICALIZATION_METHOD_ATTRIBUTE);
+        if (alg != null) {
+            SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(alg);
+            if (algorithm != null)
+                return algorithm;
+        }
+        return SignatureAlgorithm.RSA_SHA256;
+    }
+
+    public void setSignatureAlgorithm(SignatureAlgorithm algorithm) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM, algorithm.name());
+    }
+
+    public String getNameIDFormat() {
+        return clientTemplate.getAttributes().get(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE);
+    }
+    public void setNameIDFormat(String format) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE, format);
+    }
+
+    public boolean includeAuthnStatement() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT));
+    }
+
+    public void setIncludeAuthnStatement(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT, Boolean.toString(val));
+    }
+
+    public boolean forceNameIDFormat() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE));
+
+    }
+    public void setForceNameIDFormat(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE, Boolean.toString(val));
+    }
+
+    public boolean requiresRealmSignature() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE));
+    }
+
+    public void setRequiresRealmSignature(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, Boolean.toString(val));
+
+    }
+
+    public boolean forcePostBinding() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_FORCE_POST_BINDING));
+    }
+
+    public void setForcePostBinding(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_FORCE_POST_BINDING, Boolean.toString(val));
+
+    }
+    public boolean requiresAssertionSignature() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE));
+    }
+
+    public void setRequiresAssertionSignature(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE   , Boolean.toString(val));
+
+    }
+    public boolean requiresEncryption() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_ENCRYPT));
+    }
+
+
+    public void setRequiresEncryption(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_ENCRYPT, Boolean.toString(val));
+
+    }
+
+    public boolean requiresClientSignature() {
+        return "true".equals(clientTemplate.getAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE));
+    }
+
+    public void setRequiresClientSignature(boolean val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE   , Boolean.toString(val));
+
+    }
+
+    public String getClientSigningCertificate() {
+        return clientTemplate.getAttribute(SamlConfigAttributes.SAML_SIGNING_CERTIFICATE_ATTRIBUTE);
+    }
+
+    public void setClientSigningCertificate(String val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_SIGNING_CERTIFICATE_ATTRIBUTE, val);
+
+    }
+
+    public String getClientSigningPrivateKey() {
+        return clientTemplate.getAttribute(SamlConfigAttributes.SAML_SIGNING_PRIVATE_KEY);
+    }
+
+    public void setClientSigningPrivateKey(String val) {
+        clientTemplate.setAttribute(SamlConfigAttributes.SAML_SIGNING_PRIVATE_KEY, val);
+
+    }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
index 6ec5a1a..1de9f45 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
@@ -105,7 +105,7 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
 
     @Override
     public void setupClientDefaults(ClientRepresentation clientRep, ClientModel newClient) {
-        SamlClientRepresentation rep = new SamlClientRepresentation(clientRep);
+        SamlRepresentationAttributes rep = new SamlRepresentationAttributes(clientRep.getAttributes());
         SamlClient client = new SamlClient(newClient);
         if (clientRep.isStandardFlowEnabled() == null) newClient.setStandardFlowEnabled(true);
         if (rep.getCanonicalizationMethod() == null) {
@@ -136,9 +136,53 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
 
         if (rep.getClientSignature() == null) {
             client.setRequiresClientSignature(true);
+        }
+
+        if (client.requiresClientSignature() && client.getClientSigningCertificate() == null) {
             CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(newClient.getClientId());
             client.setClientSigningCertificate(info.getCertificate());
             client.setClientSigningPrivateKey(info.getPrivateKey());
+
+        }
+
+        if (clientRep.isFrontchannelLogout() == null) {
+            newClient.setFrontchannelLogout(true);
+        }
+    }
+
+    @Override
+    public void setupTemplateDefaults(ClientTemplateRepresentation clientRep, ClientTemplateModel newClient) {
+        SamlRepresentationAttributes rep = new SamlRepresentationAttributes(clientRep.getAttributes());
+        SamlClientTemplate client = new SamlClientTemplate(newClient);
+        if (clientRep.isStandardFlowEnabled() == null) newClient.setStandardFlowEnabled(true);
+        if (rep.getCanonicalizationMethod() == null) {
+            client.setCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE);
+        }
+        if (rep.getSignatureAlgorithm() == null) {
+            client.setSignatureAlgorithm(SignatureAlgorithm.RSA_SHA256);
+        }
+
+        if (rep.getNameIDFormat() == null) {
+            client.setNameIDFormat("username");
+        }
+
+        if (rep.getIncludeAuthnStatement() == null) {
+            client.setIncludeAuthnStatement(true);
+        }
+
+        if (rep.getForceNameIDFormat() == null) {
+            client.setForceNameIDFormat(false);
+        }
+
+        if (rep.getSamlServerSignature() == null) {
+            client.setRequiresRealmSignature(true);
+        }
+        if (rep.getForcePostBinding() == null) {
+            client.setForcePostBinding(true);
+        }
+
+        if (rep.getClientSignature() == null) {
+            client.setRequiresClientSignature(true);
         }
 
         if (clientRep.isFrontchannelLogout() == null) {
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index a09dd39..bd6e846 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -412,7 +412,8 @@ public class SamlService extends AuthorizationEndpointBase {
 
         @Override
         protected void verifySignature(SAMLDocumentHolder documentHolder, ClientModel client) throws VerificationException {
-            if (!"true".equals(client.getAttribute("saml.client.signature"))) {
+            SamlClient samlClient = new SamlClient(client);
+            if (!samlClient.requiresClientSignature()) {
                 return;
             }
             PublicKey publicKey = SamlProtocolUtils.getSignatureValidationKey(client);
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
index a876b19..2238e6f 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
@@ -2,10 +2,12 @@ package org.keycloak.protocol;
 
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
 import org.keycloak.services.managers.AuthenticationManager;
 
 import java.util.List;
@@ -31,10 +33,18 @@ public interface LoginProtocolFactory extends ProviderFactory<LoginProtocol> {
     Object createProtocolEndpoint(RealmModel realm, EventBuilder event, AuthenticationManager authManager);
 
     /**
-     * Setup default values for new clients.
+     * Setup default values for new clients. This expects that the representation has already set up the client
      *
      * @param rep
      * @param newClient
      */
     void setupClientDefaults(ClientRepresentation rep, ClientModel newClient);
+
+    /**
+     * Setup default values for new templates.  This expects that the representation has already set up the template
+     *
+     * @param clientRep
+     * @param newClient
+     */
+    void setupTemplateDefaults(ClientTemplateRepresentation clientRep, ClientTemplateModel newClient);
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
index 8cd0d8f..ee710ce 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -21,6 +21,7 @@ import org.keycloak.common.constants.KerberosConstants;
 import org.keycloak.common.util.UriUtils;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
@@ -32,6 +33,7 @@ import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
 import org.keycloak.protocol.oidc.mappers.UserPropertyMapper;
 import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
 import org.keycloak.services.managers.AuthenticationManager;
 
 import java.util.ArrayList;
@@ -206,4 +208,9 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
         if (rep.isPublicClient() == null) newClient.setPublicClient(true);
         if (rep.isFrontchannelLogout() == null) newClient.setFrontchannelLogout(false);
     }
+
+    @Override
+    public void setupTemplateDefaults(ClientTemplateRepresentation clientRep, ClientTemplateModel newClient) {
+
+    }
 }