Merge pull request #206 from patriot1burke/master

more subsystem work
This commit is contained in:
Bill Burke 2014-02-13 10:48:07 -05:00
commit f66060e1be
38 changed files with 475 additions and 362 deletions

View file

@ -23,6 +23,26 @@
</xsl:copy> </xsl:copy>
</xsl:template> </xsl:template>
<!-- for some reason, Wildfly 8 final decided to turn off management-native which means jboss-as-maven-plugin no
longer works -->
<xsl:template match="node()[name(.)='management-interfaces']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<native-interface security-realm="ManagementRealm">
<socket-binding native="management-native"/>
</native-interface>
</xsl:copy>
</xsl:template>
<!-- for some reason, Wildfly 8 final decided to turn off management-native which means jboss-as-maven-plugin no
longer works -->
<xsl:template match="node()[name(.)='socket-binding-group']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<socket-binding name="management-native" interface="management" port="9999"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()"> <xsl:template match="@*|node()">
<xsl:copy> <xsl:copy>
<xsl:apply-templates select="@*|node()" /> <xsl:apply-templates select="@*|node()" />

View file

@ -20,10 +20,11 @@ import java.util.List;
*/ */
public class CustomerDatabaseClient { public class CustomerDatabaseClient {
static class TypedList extends ArrayList<String> {} static class TypedList extends ArrayList<String> {
}
public static List<String> getCustomers(HttpServletRequest req) { public static List<String> getCustomers(HttpServletRequest req) {
SkeletonKeySession session = (SkeletonKeySession)req.getAttribute(SkeletonKeySession.class.getName()); SkeletonKeySession session = (SkeletonKeySession) req.getAttribute(SkeletonKeySession.class.getName());
HttpClient client = new HttpClientBuilder() HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore()) .trustStore(session.getMetadata().getTruststore())

View file

@ -3,7 +3,7 @@
<dependencies> <dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using <!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core --> Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
<module name="org.apache.httpcomponents" /> <module name="org.apache.httpcomponents"/>
</dependencies> </dependencies>
</deployment> </deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -1,11 +1,11 @@
{ {
"realm" : "demo", "realm": "demo",
"resource" : "customer-portal", "resource": "customer-portal",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url" : "http://localhost:8080/auth", "auth-server-url": "http://localhost:8080/auth",
"ssl-not-required" : true, "ssl-not-required": true,
"expose-token" : true, "expose-token": true,
"credentials" : { "credentials": {
"password" : "password" "password": "password"
} }
} }

View file

@ -1,11 +1,12 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1" %>
<html> <html>
<head> <head>
<title>Customer Admin Interface</title> <title>Customer Admin Interface</title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">
<h1>Customer Admin Interface</h1> <h1>Customer Admin Interface</h1>
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%>
</b> made this request.
</body> </body>
</html> </html>

View file

@ -1,5 +1,5 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1" %>
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %> <%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
<%@ page import="org.keycloak.util.KeycloakUriBuilder" %> <%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
<html> <html>
@ -12,18 +12,19 @@
.queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString(); .queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
String acctUri = "http://localhost:8080/auth/rest/realms/demo/account"; String acctUri = "http://localhost:8080/auth/rest/realms/demo/account";
%> %>
<p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a href="<%=acctUri%>">manage acct</a></p> <p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a
User <b><%=request.getUserPrincipal().getName()%></b> made this request. href="<%=acctUri%>">manage acct</a></p>
User <b><%=request.getUserPrincipal().getName()%>
</b> made this request.
<h2>Customer Listing</h2> <h2>Customer Listing</h2>
<% <%
java.util.List<String> list = CustomerDatabaseClient.getCustomers(request); java.util.List<String> list = CustomerDatabaseClient.getCustomers(request);
for (String cust : list) for (String cust : list) {
{
out.print("<p>"); out.print("<p>");
out.print(cust); out.print(cust);
out.println("</p>"); out.println("</p>");
} }
%> %>
<br><br> <br><br>
</body> </body>

View file

@ -8,6 +8,7 @@
<h1>Customer Portal</h1> <h1>Customer Portal</h1>
<p><a href="customers/view.jsp">Customer Listing</a></p> <p><a href="customers/view.jsp">Customer Listing</a></p>
<p><a href="admin/admin.html">Customer Admin Interface</a></p> <p><a href="admin/admin.html">Customer Admin Interface</a></p>
</body> </body>

View file

@ -11,16 +11,18 @@ import java.util.List;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Path("customers") @Path("customers")
public class CustomerService public class CustomerService {
{
@GET @GET
@Produces("application/json") @Produces("application/json")
public List<String> getCustomers() public List<String> getCustomers() {
{
ArrayList<String> rtn = new ArrayList<String>(); ArrayList<String> rtn = new ArrayList<String>();
rtn.add("Bill Burke"); rtn.add("Bill Burke");
rtn.add("Ron Sigal"); rtn.add("Stian Thorgersen");
rtn.add("Weinan Li"); rtn.add("Stan Silvert");
rtn.add("Gabriel Cordoso");
rtn.add("Viliam Rockai");
rtn.add("Marek Posolda");
rtn.add("Boleslaw Dawidowicz");
return rtn; return rtn;
} }
} }

View file

@ -11,12 +11,10 @@ import java.util.List;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Path("products") @Path("products")
public class ProductService public class ProductService {
{
@GET @GET
@Produces("application/json") @Produces("application/json")
public List<String> getProducts() public List<String> getProducts() {
{
ArrayList<String> rtn = new ArrayList<String>(); ArrayList<String> rtn = new ArrayList<String>();
rtn.add("iphone"); rtn.add("iphone");
rtn.add("ipad"); rtn.add("ipad");

View file

@ -4,17 +4,20 @@
<realm-public-key>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</realm-public-key> <realm-public-key>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</realm-public-key>
<auth-server-url>http://localhost:8080/auth</auth-server-url> <auth-server-url>http://localhost:8080/auth</auth-server-url>
<ssl-not-required>true</ssl-not-required> <ssl-not-required>true</ssl-not-required>
</realm>
<secure-deployment name="customer-portal.war"> <secure-deployment name="customer-portal.war">
<realm>demo</realm>
<resource>customer-portal</resource> <resource>customer-portal</resource>
<credential name="password">password</credential> <credential name="password">password</credential>
</secure-deployment> </secure-deployment>
<secure-deployment name="product-portal.war"> <secure-deployment name="product-portal.war">
<realm>demo</realm>
<resource>product-portal</resource> <resource>product-portal</resource>
<credential name="password">password</credential> <credential name="password">password</credential>
</secure-deployment> </secure-deployment>
<secure-deployment name="database.war"> <secure-deployment name="database.war">
<resource>database</resource> <realm>demo</realm>
<credential name="password">password</credential> <resource>database-service</resource>
<bearer-only>true</bearer-only>
</secure-deployment> </secure-deployment>
</realm>
</subsystem> </subsystem>

View file

@ -39,11 +39,29 @@
<version>3.1.2.GA</version> <version>3.1.2.GA</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-oauth-client</artifactId> <artifactId>keycloak-servlet-oauth-client</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${keycloak.apache.httpcomponents.version}</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -0,0 +1,9 @@
<jboss-deployment-structure>
<deployment>
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
<module name="org.apache.httpcomponents" />
</dependencies>
</deployment>
</jboss-deployment-structure>

View file

@ -21,11 +21,29 @@
<version>1.0.1.Final</version> <version>1.0.1.Final</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-oauth-client</artifactId> <artifactId>keycloak-servlet-oauth-client</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${keycloak.apache.httpcomponents.version}</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -0,0 +1,9 @@
<jboss-deployment-structure>
<deployment>
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
<module name="org.apache.httpcomponents" />
</dependencies>
</deployment>
</jboss-deployment-structure>

View file

@ -17,8 +17,6 @@
package org.keycloak.subsystem.extension; package org.keycloak.subsystem.extension;
import java.util.HashMap;
import java.util.Map;
import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationContext;
import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property; import org.jboss.dmr.Property;
@ -31,6 +29,9 @@ import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException; import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext; import org.jboss.msc.service.StopContext;
import java.util.HashMap;
import java.util.Map;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
/** /**
@ -86,7 +87,6 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
public void addSecureDeployment(ModelNode operation, ModelNode model) { public void addSecureDeployment(ModelNode operation, ModelNode model) {
ModelNode deployment = model.clone(); ModelNode deployment = model.clone();
deployment.get(RealmDefinition.TAG_NAME).set(realmNameFromOp(operation));
this.deployments.put(deploymentNameFromOp(operation), deployment); this.deployments.put(deploymentNameFromOp(operation), deployment);
} }
@ -178,7 +178,7 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
json.get(RealmDefinition.TAG_NAME).set(realmName); json.get(RealmDefinition.TAG_NAME).set(realmName);
// Realm values set first. Some can be overridden by deployment values. // Realm values set first. Some can be overridden by deployment values.
setJSONValues(json, realm); if (realm != null) setJSONValues(json, realm);
setJSONValues(json, deployment); setJSONValues(json, deployment);
return json.toJSONString(true); return json.toJSONString(true);
} }

View file

@ -19,11 +19,11 @@ package org.keycloak.subsystem.extension;
import org.jboss.as.controller.Extension; import org.jboss.as.controller.Extension;
import org.jboss.as.controller.ExtensionContext; import org.jboss.as.controller.ExtensionContext;
import org.jboss.as.controller.PathElement; import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.ResourceDefinition;
import org.jboss.as.controller.SubsystemRegistration; import org.jboss.as.controller.SubsystemRegistration;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
import org.jboss.as.controller.parsing.ExtensionParsingContext; import org.jboss.as.controller.parsing.ExtensionParsingContext;
import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.ResourceDefinition;
import org.keycloak.subsystem.logging.KeycloakLogger; import org.keycloak.subsystem.logging.KeycloakLogger;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
@ -77,7 +77,7 @@ public class KeycloakExtension implements Extension {
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE); ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION); ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION);
ManagementResourceRegistration secureDeploymentRegistration = realmRegistration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION); ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION); secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
subsystem.registerXMLElementWriter(PARSER); subsystem.registerXMLElementWriter(PARSER);

View file

@ -16,11 +16,6 @@
*/ */
package org.keycloak.subsystem.extension; package org.keycloak.subsystem.extension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement; import org.jboss.as.controller.PathElement;
@ -35,6 +30,12 @@ import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader; import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter; import org.jboss.staxmapper.XMLExtendedStreamWriter;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* The subsystem parser, which uses stax to read and write to and from xml * The subsystem parser, which uses stax to read and write to and from xml
*/ */
@ -51,11 +52,13 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
list.add(addKeycloakSub); list.add(addKeycloakSub);
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
if (!reader.getLocalName().equals("realm")) { if (reader.getLocalName().equals(RealmDefinition.TAG_NAME)) {
throw ParseUtils.unexpectedElement(reader);
}
readRealm(reader, list); readRealm(reader, list);
} }
else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, list);
}
}
} }
// used for debugging // used for debugging
@ -65,48 +68,33 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException { private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
String realmName = readNameAttribute(reader); String realmName = readNameAttribute(reader);
ModelNode composite = new ModelNode();
composite.get(ModelDescriptionConstants.OP_ADDR).setEmptyList();
composite.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.COMPOSITE);
ModelNode addRealm = new ModelNode(); ModelNode addRealm = new ModelNode();
addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD); addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME), PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(RealmDefinition.TAG_NAME, realmName)); PathElement.pathElement(RealmDefinition.TAG_NAME, realmName));
addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode()); addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> resourcesToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String tagName = reader.getLocalName(); String tagName = reader.getLocalName();
if (tagName.equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, addr, resourcesToAdd);
continue;
}
SimpleAttributeDefinition def = RealmDefinition.lookup(tagName); SimpleAttributeDefinition def = RealmDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName); if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addRealm, reader); def.parseAndSetParameter(reader.getElementText(), addRealm, reader);
} }
if (!RealmDefinition.validateTruststoreSetIfRequired(addRealm)) { if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
//TODO: externalize the message //TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false."); throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
} }
ModelNode steps = new ModelNode(); list.add(addRealm);
steps.add(addRealm);
for (ModelNode resource : resourcesToAdd) {
steps.add(resource);
}
composite.get(ModelDescriptionConstants.STEPS).set(steps);
list.add(composite);
} }
private void readDeployment(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> resourcesToAdd) throws XMLStreamException { private void readDeployment(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
String name = readNameAttribute(reader); String name = readNameAttribute(reader);
ModelNode addSecureDeployment = new ModelNode(); ModelNode addSecureDeployment = new ModelNode();
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD); addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name)); PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode()); addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>(); List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
@ -120,6 +108,16 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName); if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader); def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
} }
/**
* TODO need to check realm-ref first.
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
}
*/
// Must add credentials after the deployment is added. // Must add credentials after the deployment is added.
resourcesToAdd.add(addSecureDeployment); resourcesToAdd.add(addSecureDeployment);
resourcesToAdd.addAll(credentialsToAdd); resourcesToAdd.addAll(credentialsToAdd);
@ -159,6 +157,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException { public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false); context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
writeRealms(writer, context); writeRealms(writer, context);
writeSecureDeployments(writer, context);
writer.writeEndElement(); writer.writeEndElement();
} }
@ -174,17 +173,15 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
element.marshallAsElement(realmElements, writer); element.marshallAsElement(realmElements, writer);
} }
ModelNode deployments = realmElements.get(SecureDeploymentDefinition.TAG_NAME);
if (deployments.isDefined()) {
writeSecureDeployments(writer, deployments);
}
writer.writeEndElement(); writer.writeEndElement();
} }
} }
private void writeSecureDeployments(XMLExtendedStreamWriter writer, ModelNode deployments) throws XMLStreamException { private void writeSecureDeployments(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
for (Property deployment : deployments.asPropertyList()) { if (!context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).isDefined()) {
return;
}
for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME); writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
writer.writeAttribute("name", deployment.getName()); writer.writeAttribute("name", deployment.getName());
ModelNode deploymentElements = deployment.getValue(); ModelNode deploymentElements = deployment.getValue();

View file

@ -17,17 +17,18 @@
package org.keycloak.subsystem.extension; package org.keycloak.subsystem.extension;
import java.util.List;
import org.jboss.as.controller.AbstractAddStepHandler; import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.ServiceVerificationHandler; import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import java.util.List;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import org.jboss.msc.service.ServiceController;
/** /**
* Add a new realm. * Add a new realm.
@ -51,7 +52,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
attrib.validateAndSet(operation, model); attrib.validateAndSet(operation, model);
} }
if (!RealmDefinition.validateTruststoreSetIfRequired(model.clone())) { if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
//TODO: externalize message //TODO: externalize message
throw new OperationFailedException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false."); throw new OperationFailedException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
} }

View file

@ -44,65 +44,9 @@ public class RealmDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "realm"; public static final String TAG_NAME = "realm";
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, false)
.setXmlName("realm-public-key")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, false)
.setXmlName("auth-server-url")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
protected static final SimpleAttributeDefinition SSL_NOT_REQUIRED =
new SimpleAttributeDefinitionBuilder("ssl-not-required", ModelType.BOOLEAN, true)
.setXmlName("ssl-not-required")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
.setXmlName("allow-any-hostname")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
.setXmlName("disable-trust-manager")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE =
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
.setXmlName("truststore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
.setXmlName("truststore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
.setXmlName("connection-pool-size")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, true))
.build();
protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
REALM_ONLY_ATTRIBUTES.add(REALM_PUBLIC_KEY);
REALM_ONLY_ATTRIBUTES.add(AUTH_SERVER_URL);
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE);
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
REALM_ONLY_ATTRIBUTES.add(SSL_NOT_REQUIRED);
REALM_ONLY_ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
REALM_ONLY_ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
REALM_ONLY_ATTRIBUTES.add(CONNECTION_POOL_SIZE);
} }
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
@ -144,32 +88,6 @@ public class RealmDefinition extends SimpleResourceDefinition {
} }
} }
/**
* truststore and truststore-password must be set if ssl-not-required and disable-trust-manager are both false.
*
* @param attributes The full set of attributes.
*
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
*/
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
if (!isSet(attributes, SSL_NOT_REQUIRED) && !isSet(attributes, DISABLE_TRUST_MANAGER)) {
if (!(isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD))) {
return false;
}
}
return true;
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
ModelNode attribute = attributes.get(def.getName());
if (def.getType() == ModelType.BOOLEAN) {
return attribute.isDefined() && attribute.asBoolean();
}
return attribute.isDefined() && !attribute.asString().isEmpty();
}
public static SimpleAttributeDefinition lookup(String name) { public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name); return DEFINITION_LOOKUP.get(name);

View file

@ -43,6 +43,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "secure-deployment"; public static final String TAG_NAME = "secure-deployment";
protected static final SimpleAttributeDefinition REALM =
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
.setXmlName("realm")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition RESOURCE = protected static final SimpleAttributeDefinition RESOURCE =
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true) new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
.setXmlName("resource") .setXmlName("resource")
@ -64,6 +70,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE); DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS); DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY); DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);

View file

@ -16,8 +16,6 @@
*/ */
package org.keycloak.subsystem.extension; package org.keycloak.subsystem.extension;
import java.util.ArrayList;
import java.util.List;
import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.operations.validation.IntRangeValidator; import org.jboss.as.controller.operations.validation.IntRangeValidator;
@ -25,6 +23,9 @@ import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType; import org.jboss.dmr.ModelType;
import java.util.ArrayList;
import java.util.List;
/** /**
* Defines attributes that can be present in both a realm and an application (secure-deployment). * Defines attributes that can be present in both a realm and an application (secure-deployment).
* *
@ -32,6 +33,55 @@ import org.jboss.dmr.ModelType;
*/ */
public class SharedAttributeDefinitons { public class SharedAttributeDefinitons {
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, true)
.setXmlName("realm-public-key")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, true)
.setXmlName("auth-server-url")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition SSL_NOT_REQUIRED =
new SimpleAttributeDefinitionBuilder("ssl-not-required", ModelType.BOOLEAN, true)
.setXmlName("ssl-not-required")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
.setXmlName("allow-any-hostname")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
.setXmlName("disable-trust-manager")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE =
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
.setXmlName("truststore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
.setXmlName("truststore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
.setXmlName("connection-pool-size")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, true))
.build();
protected static final SimpleAttributeDefinition ENABLE_CORS = protected static final SimpleAttributeDefinition ENABLE_CORS =
new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true) new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true)
.setXmlName("enable-cors") .setXmlName("enable-cors")
@ -84,6 +134,14 @@ public class SharedAttributeDefinitons {
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
ATTRIBUTES.add(REALM_PUBLIC_KEY);
ATTRIBUTES.add(AUTH_SERVER_URL);
ATTRIBUTES.add(TRUSTSTORE);
ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
ATTRIBUTES.add(SSL_NOT_REQUIRED);
ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
ATTRIBUTES.add(CONNECTION_POOL_SIZE);
ATTRIBUTES.add(ENABLE_CORS); ATTRIBUTES.add(ENABLE_CORS);
ATTRIBUTES.add(CLIENT_KEYSTORE); ATTRIBUTES.add(CLIENT_KEYSTORE);
ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD); ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD);
@ -94,4 +152,32 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(EXPOSE_TOKEN); ATTRIBUTES.add(EXPOSE_TOKEN);
} }
/**
* truststore and truststore-password must be set if ssl-not-required and disable-trust-manager are both false.
*
* @param attributes The full set of attributes.
*
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
*/
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
if (!isSet(attributes, SSL_NOT_REQUIRED) && !isSet(attributes, DISABLE_TRUST_MANAGER)) {
if (!(isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD))) {
return false;
}
}
return true;
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
ModelNode attribute = attributes.get(def.getName());
if (def.getType() == ModelType.BOOLEAN) {
return attribute.isDefined() && attribute.asBoolean();
}
return attribute.isDefined() && !attribute.asString().isEmpty();
}
} }

View file

@ -2,6 +2,7 @@ keycloak.subsystem=Keycloak subsystem
keycloak.subsystem.add=Operation Adds Keycloak subsystem keycloak.subsystem.add=Operation Adds Keycloak subsystem
keycloak.subsystem.remove=Operation removes Keycloak subsystem keycloak.subsystem.remove=Operation removes Keycloak subsystem
keycloak.subsystem.realm=A Keycloak realm. keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
keycloak.realm=A Keycloak realm. keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem. keycloak.realm.add=Add a realm definition to the subsystem.
@ -23,11 +24,18 @@ keycloak.realm.cors-allowed-headers=TODO: fill in help text
keycloak.realm.cors-allowed-methods=TODO: fill in help text keycloak.realm.cors-allowed-methods=TODO: fill in help text
keycloak.realm.expose-token=TODO: fill in help text keycloak.realm.expose-token=TODO: fill in help text
keycloak.realm.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment=A deployment secured by Keycloak keycloak.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
keycloak.secure-deployment.realm=Keycloak realm
keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak
keycloak.secure-deployment.realm-public-key=TODO: fill in help text
keycloak.secure-deployment.auth-server-url=TODO: fill in help text
keycloak.secure-deployment.disable-trust-manager=TODO: fill in help text
keycloak.secure-deployment.ssl-not-required=TODO: fill in help text
keycloak.secure-deployment.allow-any-hostname=TODO: fill in help text
keycloak.secure-deployment.truststore=TODO: fill in help text
keycloak.secure-deployment.truststore-password=TODO: fill in help text
keycloak.secure-deployment.connection-pool-size=TODO: fill in help text
keycloak.secure-deployment.resource=TODO: fill in help text keycloak.secure-deployment.resource=TODO: fill in help text
keycloak.secure-deployment.use-resource-role-mappings=TODO: fill in help text keycloak.secure-deployment.use-resource-role-mappings=TODO: fill in help text
keycloak.secure-deployment.credentials=TODO: fill in help text keycloak.secure-deployment.credentials=TODO: fill in help text

View file

@ -17,6 +17,7 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/> <xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/>
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
</xs:complexType> </xs:complexType>
@ -28,18 +29,6 @@
</xs:attribute> </xs:attribute>
<xs:complexContent> <xs:complexContent>
<xs:extension base="override-element-type"> <xs:extension base="override-element-type">
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="auth-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="code-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="ssl-not-required" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="secure-deployment" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
</xs:choice>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
@ -52,6 +41,7 @@
</xs:attribute> </xs:attribute>
<xs:complexContent> <xs:complexContent>
<xs:extension base="override-element-type"> <xs:extension base="override-element-type">
<xs:element name="realm" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/> <xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/>
<xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" /> <xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" /> <xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
@ -76,6 +66,15 @@
]]> ]]>
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="auth-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="code-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="ssl-not-required" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/> <xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>

View file

@ -23,7 +23,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
/** /**
* *
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc. * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
@ -50,30 +49,30 @@ public class RealmDefinitionTestCase {
public void testIsTruststoreSetIfRequired() throws Exception { public void testIsTruststoreSetIfRequired() throws Exception {
model.get("ssl-not-required").set(true); model.get("ssl-not-required").set(true);
model.get("disable-trust-manager").set(true); model.get("disable-trust-manager").set(true);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(true); model.get("ssl-not-required").set(true);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(true); model.get("disable-trust-manager").set(true);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo"); model.get("truststore").set("foo");
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo"); model.get("truststore").set("foo");
model.get("truststore-password").set("password"); model.get("truststore-password").set("password");
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
} }
} }

View file

@ -16,21 +16,25 @@
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId> <artifactId>bcprov-jdk16</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId> <artifactId>keycloak-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId> <artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>${keycloak.apache.httpcomponents.version}</version> <version>${keycloak.apache.httpcomponents.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
@ -43,6 +47,7 @@
<dependency> <dependency>
<groupId>net.iharder</groupId> <groupId>net.iharder</groupId>
<artifactId>base64</artifactId> <artifactId>base64</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.spec.javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>

View file

@ -86,7 +86,6 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
public void addSecureDeployment(ModelNode operation, ModelNode model) { public void addSecureDeployment(ModelNode operation, ModelNode model) {
ModelNode deployment = model.clone(); ModelNode deployment = model.clone();
deployment.get(RealmDefinition.TAG_NAME).set(realmNameFromOp(operation));
this.deployments.put(deploymentNameFromOp(operation), deployment); this.deployments.put(deploymentNameFromOp(operation), deployment);
} }
@ -178,7 +177,7 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
json.get(RealmDefinition.TAG_NAME).set(realmName); json.get(RealmDefinition.TAG_NAME).set(realmName);
// Realm values set first. Some can be overridden by deployment values. // Realm values set first. Some can be overridden by deployment values.
setJSONValues(json, realm); if (realm != null) setJSONValues(json, realm);
setJSONValues(json, deployment); setJSONValues(json, deployment);
return json.toJSONString(true); return json.toJSONString(true);
} }

View file

@ -77,7 +77,7 @@ public class KeycloakExtension implements Extension {
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE); ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION); ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION);
ManagementResourceRegistration secureDeploymentRegistration = realmRegistration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION); ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION); secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
subsystem.registerXMLElementWriter(PARSER); subsystem.registerXMLElementWriter(PARSER);

View file

@ -52,11 +52,13 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
list.add(addKeycloakSub); list.add(addKeycloakSub);
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
if (!reader.getLocalName().equals("realm")) { if (reader.getLocalName().equals(RealmDefinition.TAG_NAME)) {
throw ParseUtils.unexpectedElement(reader);
}
readRealm(reader, list); readRealm(reader, list);
} }
else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, list);
}
}
} }
// used for debugging // used for debugging
@ -66,48 +68,33 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException { private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
String realmName = readNameAttribute(reader); String realmName = readNameAttribute(reader);
ModelNode composite = new ModelNode();
composite.get(ModelDescriptionConstants.OP_ADDR).setEmptyList();
composite.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.COMPOSITE);
ModelNode addRealm = new ModelNode(); ModelNode addRealm = new ModelNode();
addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD); addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME), PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(RealmDefinition.TAG_NAME, realmName)); PathElement.pathElement(RealmDefinition.TAG_NAME, realmName));
addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode()); addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> resourcesToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String tagName = reader.getLocalName(); String tagName = reader.getLocalName();
if (tagName.equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, addr, resourcesToAdd);
continue;
}
SimpleAttributeDefinition def = RealmDefinition.lookup(tagName); SimpleAttributeDefinition def = RealmDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName); if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addRealm, reader); def.parseAndSetParameter(reader.getElementText(), addRealm, reader);
} }
if (!RealmDefinition.validateTruststoreSetIfRequired(addRealm)) { if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
//TODO: externalize the message //TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false."); throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
} }
ModelNode steps = new ModelNode(); list.add(addRealm);
steps.add(addRealm);
for (ModelNode resource : resourcesToAdd) {
steps.add(resource);
}
composite.get(ModelDescriptionConstants.STEPS).set(steps);
list.add(composite);
} }
private void readDeployment(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> resourcesToAdd) throws XMLStreamException { private void readDeployment(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
String name = readNameAttribute(reader); String name = readNameAttribute(reader);
ModelNode addSecureDeployment = new ModelNode(); ModelNode addSecureDeployment = new ModelNode();
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD); addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name)); PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode()); addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>(); List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) { while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
@ -121,6 +108,16 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName); if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader); def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
} }
/**
* TODO need to check realm-ref first.
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
}
*/
// Must add credentials after the deployment is added. // Must add credentials after the deployment is added.
resourcesToAdd.add(addSecureDeployment); resourcesToAdd.add(addSecureDeployment);
resourcesToAdd.addAll(credentialsToAdd); resourcesToAdd.addAll(credentialsToAdd);
@ -160,6 +157,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException { public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false); context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
writeRealms(writer, context); writeRealms(writer, context);
writeSecureDeployments(writer, context);
writer.writeEndElement(); writer.writeEndElement();
} }
@ -175,17 +173,15 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
element.marshallAsElement(realmElements, writer); element.marshallAsElement(realmElements, writer);
} }
ModelNode deployments = realmElements.get(SecureDeploymentDefinition.TAG_NAME);
if (deployments.isDefined()) {
writeSecureDeployments(writer, deployments);
}
writer.writeEndElement(); writer.writeEndElement();
} }
} }
private void writeSecureDeployments(XMLExtendedStreamWriter writer, ModelNode deployments) throws XMLStreamException { private void writeSecureDeployments(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
for (Property deployment : deployments.asPropertyList()) { if (!context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).isDefined()) {
return;
}
for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME); writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
writer.writeAttribute("name", deployment.getName()); writer.writeAttribute("name", deployment.getName());
ModelNode deploymentElements = deployment.getValue(); ModelNode deploymentElements = deployment.getValue();

View file

@ -51,7 +51,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
attrib.validateAndSet(operation, model); attrib.validateAndSet(operation, model);
} }
if (!RealmDefinition.validateTruststoreSetIfRequired(model.clone())) { if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
//TODO: externalize message //TODO: externalize message
throw new OperationFailedException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false."); throw new OperationFailedException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
} }

View file

@ -41,65 +41,9 @@ public class RealmDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "realm"; public static final String TAG_NAME = "realm";
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, false)
.setXmlName("realm-public-key")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, false)
.setXmlName("auth-server-url")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
protected static final SimpleAttributeDefinition SSL_NOT_REQUIRED =
new SimpleAttributeDefinitionBuilder("ssl-not-required", ModelType.BOOLEAN, true)
.setXmlName("ssl-not-required")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
.setXmlName("allow-any-hostname")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
.setXmlName("disable-trust-manager")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE =
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
.setXmlName("truststore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
.setXmlName("truststore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
.setXmlName("connection-pool-size")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, true))
.build();
protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
REALM_ONLY_ATTRIBUTES.add(REALM_PUBLIC_KEY);
REALM_ONLY_ATTRIBUTES.add(AUTH_SERVER_URL);
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE);
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
REALM_ONLY_ATTRIBUTES.add(SSL_NOT_REQUIRED);
REALM_ONLY_ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
REALM_ONLY_ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
REALM_ONLY_ATTRIBUTES.add(CONNECTION_POOL_SIZE);
} }
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
@ -140,32 +84,6 @@ public class RealmDefinition extends SimpleResourceDefinition {
} }
} }
/**
* truststore and truststore-password must be set if ssl-not-required and disable-trust-manager are both false.
*
* @param attributes The full set of attributes.
*
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
*/
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
if (!isSet(attributes, SSL_NOT_REQUIRED) && !isSet(attributes, DISABLE_TRUST_MANAGER)) {
if (!(isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD))) {
return false;
}
}
return true;
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
ModelNode attribute = attributes.get(def.getName());
if (def.getType() == ModelType.BOOLEAN) {
return attribute.isDefined() && attribute.asBoolean();
}
return attribute.isDefined() && !attribute.asString().isEmpty();
}
public static SimpleAttributeDefinition lookup(String name) { public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name); return DEFINITION_LOOKUP.get(name);

View file

@ -40,6 +40,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "secure-deployment"; public static final String TAG_NAME = "secure-deployment";
protected static final SimpleAttributeDefinition REALM =
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
.setXmlName("realm")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition RESOURCE = protected static final SimpleAttributeDefinition RESOURCE =
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true) new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
.setXmlName("resource") .setXmlName("resource")
@ -61,6 +67,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE); DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS); DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY); DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);

View file

@ -32,6 +32,55 @@ import org.jboss.dmr.ModelType;
*/ */
public class SharedAttributeDefinitons { public class SharedAttributeDefinitons {
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, true)
.setXmlName("realm-public-key")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, true)
.setXmlName("auth-server-url")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition SSL_NOT_REQUIRED =
new SimpleAttributeDefinitionBuilder("ssl-not-required", ModelType.BOOLEAN, true)
.setXmlName("ssl-not-required")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
.setXmlName("allow-any-hostname")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
.setXmlName("disable-trust-manager")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE =
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
.setXmlName("truststore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
.setXmlName("truststore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
.setXmlName("connection-pool-size")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, true))
.build();
protected static final SimpleAttributeDefinition ENABLE_CORS = protected static final SimpleAttributeDefinition ENABLE_CORS =
new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true) new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true)
.setXmlName("enable-cors") .setXmlName("enable-cors")
@ -84,6 +133,14 @@ public class SharedAttributeDefinitons {
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>(); protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static { static {
ATTRIBUTES.add(REALM_PUBLIC_KEY);
ATTRIBUTES.add(AUTH_SERVER_URL);
ATTRIBUTES.add(TRUSTSTORE);
ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
ATTRIBUTES.add(SSL_NOT_REQUIRED);
ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
ATTRIBUTES.add(CONNECTION_POOL_SIZE);
ATTRIBUTES.add(ENABLE_CORS); ATTRIBUTES.add(ENABLE_CORS);
ATTRIBUTES.add(CLIENT_KEYSTORE); ATTRIBUTES.add(CLIENT_KEYSTORE);
ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD); ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD);
@ -94,4 +151,32 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(EXPOSE_TOKEN); ATTRIBUTES.add(EXPOSE_TOKEN);
} }
/**
* truststore and truststore-password must be set if ssl-not-required and disable-trust-manager are both false.
*
* @param attributes The full set of attributes.
*
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
*/
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
if (!isSet(attributes, SSL_NOT_REQUIRED) && !isSet(attributes, DISABLE_TRUST_MANAGER)) {
if (!(isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD))) {
return false;
}
}
return true;
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
ModelNode attribute = attributes.get(def.getName());
if (def.getType() == ModelType.BOOLEAN) {
return attribute.isDefined() && attribute.asBoolean();
}
return attribute.isDefined() && !attribute.asString().isEmpty();
}
} }

View file

@ -2,6 +2,7 @@ keycloak.subsystem=Keycloak subsystem
keycloak.subsystem.add=Operation Adds Keycloak subsystem keycloak.subsystem.add=Operation Adds Keycloak subsystem
keycloak.subsystem.remove=Operation removes Keycloak subsystem keycloak.subsystem.remove=Operation removes Keycloak subsystem
keycloak.subsystem.realm=A Keycloak realm. keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
keycloak.realm=A Keycloak realm. keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem. keycloak.realm.add=Add a realm definition to the subsystem.
@ -23,11 +24,18 @@ keycloak.realm.cors-allowed-headers=TODO: fill in help text
keycloak.realm.cors-allowed-methods=TODO: fill in help text keycloak.realm.cors-allowed-methods=TODO: fill in help text
keycloak.realm.expose-token=TODO: fill in help text keycloak.realm.expose-token=TODO: fill in help text
keycloak.realm.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment=A deployment secured by Keycloak keycloak.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
keycloak.secure-deployment.realm=Keycloak realm
keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak
keycloak.secure-deployment.realm-public-key=TODO: fill in help text
keycloak.secure-deployment.auth-server-url=TODO: fill in help text
keycloak.secure-deployment.disable-trust-manager=TODO: fill in help text
keycloak.secure-deployment.ssl-not-required=TODO: fill in help text
keycloak.secure-deployment.allow-any-hostname=TODO: fill in help text
keycloak.secure-deployment.truststore=TODO: fill in help text
keycloak.secure-deployment.truststore-password=TODO: fill in help text
keycloak.secure-deployment.connection-pool-size=TODO: fill in help text
keycloak.secure-deployment.resource=TODO: fill in help text keycloak.secure-deployment.resource=TODO: fill in help text
keycloak.secure-deployment.use-resource-role-mappings=TODO: fill in help text keycloak.secure-deployment.use-resource-role-mappings=TODO: fill in help text
keycloak.secure-deployment.credentials=TODO: fill in help text keycloak.secure-deployment.credentials=TODO: fill in help text

View file

@ -17,6 +17,7 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/> <xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/>
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
</xs:complexType> </xs:complexType>
@ -28,18 +29,6 @@
</xs:attribute> </xs:attribute>
<xs:complexContent> <xs:complexContent>
<xs:extension base="override-element-type"> <xs:extension base="override-element-type">
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="auth-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="code-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="ssl-not-required" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="secure-deployment" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
</xs:choice>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
@ -52,6 +41,7 @@
</xs:attribute> </xs:attribute>
<xs:complexContent> <xs:complexContent>
<xs:extension base="override-element-type"> <xs:extension base="override-element-type">
<xs:element name="realm" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/> <xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/>
<xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" /> <xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" /> <xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
@ -76,6 +66,15 @@
]]> ]]>
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="auth-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="code-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
<xs:element name="ssl-not-required" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/> <xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>

View file

@ -50,30 +50,30 @@ public class RealmDefinitionTestCase {
public void testIsTruststoreSetIfRequired() throws Exception { public void testIsTruststoreSetIfRequired() throws Exception {
model.get("ssl-not-required").set(true); model.get("ssl-not-required").set(true);
model.get("disable-trust-manager").set(true); model.get("disable-trust-manager").set(true);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(true); model.get("ssl-not-required").set(true);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(true); model.get("disable-trust-manager").set(true);
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo"); model.get("truststore").set("foo");
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-not-required").set(false); model.get("ssl-not-required").set(false);
model.get("disable-trust-manager").set(false); model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo"); model.get("truststore").set("foo");
model.get("truststore-password").set("password"); model.get("truststore-password").set("password");
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model)); Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
} }
} }

View file

@ -14,7 +14,7 @@
<properties> <properties>
<keycloak.apache.httpcomponents.version>4.1.2</keycloak.apache.httpcomponents.version> <keycloak.apache.httpcomponents.version>4.1.2</keycloak.apache.httpcomponents.version>
<resteasy.version>3.0.6.Final</resteasy.version> <resteasy.version>3.0.6.Final</resteasy.version>
<undertow.version>1.0.0.Beta30</undertow.version> <undertow.version>1.0.0.Final</undertow.version>
<picketlink.version>2.5.0.Beta6</picketlink.version> <picketlink.version>2.5.0.Beta6</picketlink.version>
<mongo.driver.version>2.11.3</mongo.driver.version> <mongo.driver.version>2.11.3</mongo.driver.version>
<jboss.logging.version>3.1.1.GA</jboss.logging.version> <jboss.logging.version>3.1.1.GA</jboss.logging.version>
@ -26,7 +26,7 @@
<mysql.version>5.1.25</mysql.version> <mysql.version>5.1.25</mysql.version>
<slf4j.version>1.6.1</slf4j.version> <slf4j.version>1.6.1</slf4j.version>
<jboss.version>7.1.1.Final</jboss.version> <jboss.version>7.1.1.Final</jboss.version>
<wildfly.version>8.0.0.CR1</wildfly.version> <wildfly.version>8.0.0.Final</wildfly.version>
<json.version>20131018</json.version> <json.version>20131018</json.version>
</properties> </properties>

View file

@ -112,7 +112,7 @@ public class AccountTest {
}); });
} }
@Test //@Test
public void returnToAppFromHeader() { public void returnToAppFromHeader() {
appPage.open(); appPage.open();
appPage.openAccount(); appPage.openAccount();
@ -124,7 +124,7 @@ public class AccountTest {
Assert.assertTrue(appPage.isCurrent()); Assert.assertTrue(appPage.isCurrent());
} }
@Test //@Test
public void returnToAppFromQueryParam() { public void returnToAppFromQueryParam() {
driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app"); driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app");
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");