KEYCLOAK-4208 restructure spring config to match servlet spec. updating jetty, tomcat and undertow

This commit is contained in:
Alexander Schwartz 2017-02-05 23:01:19 +01:00
parent 2a8b2aabb9
commit 4d5fd0b75e
3 changed files with 77 additions and 49 deletions

View file

@ -56,7 +56,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty92-adapter</artifactId> <artifactId>keycloak-jetty93-adapter</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>

View file

@ -141,10 +141,10 @@ public class KeycloakSpringBootConfiguration {
List<io.undertow.servlet.api.SecurityConstraint> undertowSecurityConstraints = new ArrayList<io.undertow.servlet.api.SecurityConstraint>(); List<io.undertow.servlet.api.SecurityConstraint> undertowSecurityConstraints = new ArrayList<io.undertow.servlet.api.SecurityConstraint>();
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) { for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint(); io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
undertowSecurityConstraint.addRolesAllowed(collectionDefinition.getAuthRoles()); undertowSecurityConstraint.addRolesAllowed(constraintDefinition.getAuthRoles());
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
WebResourceCollection webResourceCollection = new WebResourceCollection(); WebResourceCollection webResourceCollection = new WebResourceCollection();
webResourceCollection.addHttpMethods(collectionDefinition.getMethods()); webResourceCollection.addHttpMethods(collectionDefinition.getMethods());
@ -153,8 +153,9 @@ public class KeycloakSpringBootConfiguration {
undertowSecurityConstraint.addWebResourceCollections(webResourceCollection); undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
undertowSecurityConstraints.add(undertowSecurityConstraint);
} }
undertowSecurityConstraints.add(undertowSecurityConstraint);
} }
return undertowSecurityConstraints; return undertowSecurityConstraints;
} }
@ -174,38 +175,62 @@ public class KeycloakSpringBootConfiguration {
KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator(); KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator();
keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver()); keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver());
/* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example
on how to map servlet spec to Constraints */
List<ConstraintMapping> jettyConstraintMappings = new ArrayList<ConstraintMapping>(); List<ConstraintMapping> jettyConstraintMappings = new ArrayList<ConstraintMapping>();
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) { for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition
.getSecurityCollections()) { .getSecurityCollections()) {
// securityCollection matches servlet spec's web-resource-collection
Constraint jettyConstraint = new Constraint(); Constraint jettyConstraint = new Constraint();
jettyConstraint.setName(securityCollectionDefinition.getName());
if (constraintDefinition.getAuthRoles().size() > 0) {
jettyConstraint.setAuthenticate(true); jettyConstraint.setAuthenticate(true);
jettyConstraint.setRoles(constraintDefinition.getAuthRoles().toArray(new String[0]));
}
if (securityCollectionDefinition.getName() != null) {
jettyConstraint.setName(securityCollectionDefinition.getName()); jettyConstraint.setName(securityCollectionDefinition.getName());
}
jettyConstraint.setRoles(securityCollectionDefinition.getAuthRoles().toArray(new String[0])); // according to the servlet spec each security-constraint has at least one URL pattern
for(String pattern : securityCollectionDefinition.getPatterns()) {
ConstraintMapping jettyConstraintMapping = new ConstraintMapping(); /* the following code is asymmetric as Jetty's ConstraintMapping accepts only one allowed HTTP method,
if (securityCollectionDefinition.getPatterns().size() > 0) { but multiple omitted methods. Therefore we add one ConstraintMapping for each allowed
//First pattern wins mapping but only one mapping in the cases of omitted methods or no methods.
jettyConstraintMapping.setPathSpec(securityCollectionDefinition.getPatterns().get(0)); */
jettyConstraintMapping.setConstraint(jettyConstraint);
}
if (securityCollectionDefinition.getMethods().size() > 0) { if (securityCollectionDefinition.getMethods().size() > 0) {
//First method wins // according to the servlet spec we have either methods ...
jettyConstraintMapping.setMethod(securityCollectionDefinition.getMethods().get(0)); for(String method : securityCollectionDefinition.getMethods()) {
} ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
jettyConstraintMapping.setMethod(method);
}
} else if (securityCollectionDefinition.getOmittedMethods().size() > 0){
// ... omitted methods ...
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
jettyConstraintMapping.setMethodOmissions( jettyConstraintMapping.setMethodOmissions(
securityCollectionDefinition.getOmittedMethods().toArray(new String[0])); securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
} else {
// ... or no methods at all
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping); jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
}
}
} }
} }
@ -235,19 +260,21 @@ public class KeycloakSpringBootConfiguration {
Set<String> authRoles = new HashSet<String>(); Set<String> authRoles = new HashSet<String>();
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) { for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) { for (String authRole : constraint.getAuthRoles()) {
for (String authRole : collection.getAuthRoles()) {
if (!authRoles.contains(authRole)) { if (!authRoles.contains(authRole)) {
context.addSecurityRole(authRole); context.addSecurityRole(authRole);
authRoles.add(authRole); authRoles.add(authRole);
} }
} }
} }
}
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) { for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
SecurityConstraint tomcatConstraint = new SecurityConstraint(); SecurityConstraint tomcatConstraint = new SecurityConstraint();
for (String authRole : constraint.getAuthRoles()) {
tomcatConstraint.addAuthRole(authRole);
}
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) { for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
SecurityCollection tomcatSecCollection = new SecurityCollection(); SecurityCollection tomcatSecCollection = new SecurityCollection();
@ -258,10 +285,6 @@ public class KeycloakSpringBootConfiguration {
tomcatSecCollection.setDescription(collection.getDescription()); tomcatSecCollection.setDescription(collection.getDescription());
} }
for (String authRole : collection.getAuthRoles()) {
tomcatConstraint.addAuthRole(authRole);
}
for (String pattern : collection.getPatterns()) { for (String pattern : collection.getPatterns()) {
tomcatSecCollection.addPattern(pattern); tomcatSecCollection.addPattern(pattern);
} }

View file

@ -43,12 +43,20 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
*/ */
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>(); private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
/**
* This matches security-constraint of the servlet spec
*/
@ConfigurationProperties() @ConfigurationProperties()
public static class SecurityConstraint { public static class SecurityConstraint {
/** /**
* A list of security collections * A list of security collections
*/ */
private List<SecurityCollection> securityCollections = new ArrayList<SecurityCollection>(); private List<SecurityCollection> securityCollections = new ArrayList<SecurityCollection>();
private List<String> authRoles = new ArrayList<String>();
public List<String> getAuthRoles() {
return authRoles;
}
public List<SecurityCollection> getSecurityCollections() { public List<SecurityCollection> getSecurityCollections() {
return securityCollections; return securityCollections;
@ -57,7 +65,16 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
public void setSecurityCollections(List<SecurityCollection> securityCollections) { public void setSecurityCollections(List<SecurityCollection> securityCollections) {
this.securityCollections = securityCollections; this.securityCollections = securityCollections;
} }
public void setAuthRoles(List<String> authRoles) {
this.authRoles = authRoles;
} }
}
/**
* This matches web-resource-collection of the servlet spec
*/
@ConfigurationProperties() @ConfigurationProperties()
public static class SecurityCollection { public static class SecurityCollection {
/** /**
@ -68,10 +85,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
* The description of your security collection * The description of your security collection
*/ */
private String description; private String description;
/**
* A list of roles that applies for this security collection
*/
private List<String> authRoles = new ArrayList<String>();
/** /**
* A list of URL patterns that should match to apply the security collection * A list of URL patterns that should match to apply the security collection
*/ */
@ -85,10 +98,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
*/ */
private List<String> omittedMethods = new ArrayList<String>(); private List<String> omittedMethods = new ArrayList<String>();
public List<String> getAuthRoles() {
return authRoles;
}
public List<String> getPatterns() { public List<String> getPatterns() {
return patterns; return patterns;
} }
@ -117,10 +126,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
this.description = description; this.description = description;
} }
public void setAuthRoles(List<String> authRoles) {
this.authRoles = authRoles;
}
public void setPatterns(List<String> patterns) { public void setPatterns(List<String> patterns) {
this.patterns = patterns; this.patterns = patterns;
} }