Skip to content

Commit 43e0426

Browse files
committed
Merge branch 'release/1.0.0'
2 parents 8f7b6b0 + 113d23a commit 43e0426

File tree

20 files changed

+432
-115
lines changed

20 files changed

+432
-115
lines changed

CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
# Change log
22
All notable changes to this project are documented in this file following the [Keep a CHANGELOG](http://keepachangelog.com) conventions.
33

4+
5+
## 1.0.0
6+
### Changed
7+
- Maven project version: authzforce-ce-parent: 7.4.0 -> Upgrade Apache CXF version (to fix a CVE): 3.2.5
8+
- Maven dependency versions:
9+
- Spring Framework: 4.3.18 (fix CVE-2018-8014)
10+
- authzforce-ce-jaxrs-utils: 1.2.0
11+
- authzforce-ce-xacml-json-model: 2.0.0
12+
13+
### Fixed
14+
- Spring Framework logging: replaced commons-logging with jcl-over-slf4j for SLF4j logging
15+
16+
### Added
17+
- - #1: Authorization decision caching
18+
- SSL support with client certificate authentication:
19+
- New configuration property `org.ow2.authzforce.kafka.pep.http.client.cfg.location` to [configure CXF HTTP client](https://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport(includingSSLsupport)-ConfiguringSSLSupport), esp. SSL settings
20+
21+
422
## 0.2.0
523
### Added
624
- XACML Request template file (`request.xacml.json.ft`) as part of the assembled package (`tar.gz`), so that it can be customized (by editing the file) depending on the use case

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ To enable the authorizer on Kafka, set the server's property:
2727

2828
To enable XACML evaluation, set the extra following authorizer properties:
2929
* **`org.ow2.authzforce.kafka.pep.xacml.pdp.url`**: XACML PDP resource's URL, as defined by [REST Profile of XACML 3.0](http://docs.oasis-open.org/xacml/xacml-rest/v1.0/xacml-rest-v1.0.html), §2.2.2, e.g. `https://serverhostname/services/pdp` for a [AuthzForce RESTful PDP](https://github.com/authzforce/restful-pdp) instance, or `https://serverhostname/authzforce-ce/domains/XXX/pdp` for a domain `XXX` on a [AuthzForce Server](https://github.com/authzforce/server) instance.
30+
* **`org.ow2.authzforce.kafka.pep.http.client.cfg.location`**: location (URL supported by Spring {@link org.springframework.util.ResourceUtils}) of the HTTP client configuration as defined by <a href="https://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport(includingSSLsupport)-UsingConfiguration">Apache CXF format</a>, required for SSL settings
3031
* **`org.ow2.authzforce.kafka.pep.authz.cache.size.max`:** maximum number of authorization decisions cached in memory (performance optimization). Cache disabled iff not strictly positive integer. If cache enabled and an access request matches a previous one in cache, the corresponding decision is retrieved from cache directly (no decision evaluation).
3132
* **`org.ow2.authzforce.kafka.pep.xacml.req.tmpl.location`:** location of a file that contains a [Freemarker](https://freemarker.apache.org/) template of XACML Request formatted according to [JSON Profile of XACML 3.0](http://docs.oasis-open.org/xacml/xacml-json-http/v1.0/xacml-json-http-v1.0.html), in which you can use [Freemarker expressions](https://freemarker.apache.org/docs/dgui_template_exp.html), enclosed between `${` and `}`, and have access to the following [top-level variables](https://freemarker.apache.org/docs/dgui_template_exp.html#dgui_template_exp_var_toplevel) from Kafka's authorization context:
3233

pom.xml

+60-12
Original file line numberDiff line numberDiff line change
@@ -19,36 +19,77 @@
1919
<organizationUrl>http://thalesgroup.com</organizationUrl>
2020
</developer>
2121
</developers>
22-
<scm>
23-
<connection>scm:git:https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer.git</connection>
24-
<developerConnection>scm:git:https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer.git</developerConnection>
25-
<tag>HEAD</tag>
26-
<url>https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer</url>
27-
</scm>
22+
<scm>
23+
<connection>scm:git:https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer.git</connection>
24+
<developerConnection>scm:git:https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer.git</developerConnection>
25+
<tag>HEAD</tag>
26+
<url>https://github.com/DRIVER-EU/kafka-combined-acl-xacml-authorizer</url>
27+
</scm>
2828
<repositories>
2929
<repository>
3030
<!-- Required by owasp dependency-check plugin for find info (POM) about dependency org.everit.json.schema in child modules -->
3131
<id>jitpack.io</id>
3232
<url>https://jitpack.io</url>
3333
</repository>
3434
</repositories>
35+
<properties>
36+
<!-- Remove spring.version after update authzforce-ce-parent to 7.5.0 -->
37+
<spring.version>4.3.18.RELEASE</spring.version>
38+
</properties>
39+
<dependencyManagement>
40+
<dependencies>
41+
<dependency>
42+
<groupId>org.springframework</groupId>
43+
<artifactId>spring-core</artifactId>
44+
<version>${spring.version}</version>
45+
<exclusions>
46+
<exclusion>
47+
<!-- Replaced by jcl-over-slf4j dependency for redirecting logs to slf4j, see http://www.slf4j.org/legacy.html -->
48+
<artifactId>commons-logging</artifactId>
49+
<groupId>commons-logging</groupId>
50+
</exclusion>
51+
</exclusions>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.springframework</groupId>
55+
<artifactId>spring-context</artifactId>
56+
<version>${spring.version}</version>
57+
<exclusions>
58+
<exclusion>
59+
<!-- Replaced by jcl-over-slf4j dependency for redirecting logs to slf4j, see http://www.slf4j.org/legacy.html -->
60+
<artifactId>commons-logging</artifactId>
61+
<groupId>commons-logging</groupId>
62+
</exclusion>
63+
</exclusions>
64+
</dependency>
65+
</dependencies>
66+
</dependencyManagement>
3567
<dependencies>
68+
<dependency>
69+
<groupId>org.apache.kafka</groupId>
70+
<artifactId>kafka_2.12</artifactId>
71+
<version>1.1.0</version>
72+
<scope>provided</scope>
73+
</dependency>
3674
<dependency>
3775
<groupId>org.slf4j</groupId>
3876
<artifactId>slf4j-api</artifactId>
3977
<scope>provided</scope>
4078
</dependency>
4179
<dependency>
42-
<groupId>org.apache.kafka</groupId>
43-
<artifactId>kafka_2.12</artifactId>
44-
<version>1.1.0</version>
45-
<scope>provided</scope>
80+
<groupId>org.slf4j</groupId>
81+
<artifactId>jcl-over-slf4j</artifactId>
4682
</dependency>
4783
<dependency>
4884
<groupId>org.freemarker</groupId>
4985
<artifactId>freemarker</artifactId>
5086
<version>2.3.23</version>
5187
</dependency>
88+
<!-- Needed when using CXF HTTP client XML configuration -->
89+
<dependency>
90+
<groupId>org.springframework</groupId>
91+
<artifactId>spring-context</artifactId>
92+
</dependency>
5293
<dependency>
5394
<groupId>org.apache.cxf</groupId>
5495
<artifactId>cxf-rt-rs-client</artifactId>
@@ -62,6 +103,13 @@
62103
<groupId>org.ow2.authzforce</groupId>
63104
<artifactId>authzforce-ce-jaxrs-utils</artifactId>
64105
<version>1.2.0</version>
106+
<exclusions>
107+
<exclusion>
108+
<!-- Replaced by jcl-over-slf4j dependency for redirecting logs to slf4j, see http://www.slf4j.org/legacy.html -->
109+
<artifactId>commons-logging</artifactId>
110+
<groupId>commons-logging</groupId>
111+
</exclusion>
112+
</exclusions>
65113
</dependency>
66114
<dependency>
67115
<groupId>ch.qos.logback</groupId>
@@ -71,7 +119,7 @@
71119
<dependency>
72120
<groupId>org.springframework.boot</groupId>
73121
<artifactId>spring-boot-starter-test</artifactId>
74-
<version>1.5.11.RELEASE</version>
122+
<version>1.5.14.RELEASE</version>
75123
<scope>test</scope>
76124
<!-- jsonassert depends on com.vaadin.external.google:android-json whose classes conflict with org.json:json -->
77125
<exclusions>
@@ -90,7 +138,7 @@
90138
<dependency>
91139
<groupId>eu.driver</groupId>
92140
<artifactId>driver-testbed-sec-authz-service</artifactId>
93-
<version>1.0.0</version>
141+
<version>1.1.0</version>
94142
<scope>test</scope>
95143
</dependency>
96144
</dependencies>

src/main/java/org/ow2/authzforce/kafka/pep/CombinedXacmlAclAuthorizer.java

+28-3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
* </ul>
7373
* </li>
7474
* <li>{@value #AUTHZ_CACHE_SIZE_MAX}: maximum number of authorization decisions cached in memory. Cache is disabled iff the property value is undefined or not strictly positive.</li>
75+
* <li>{@value #HTTP_CLIENT_CFG_LOCATION}: location (URL supported by Spring {@link org.springframework.util.ResourceUtils}) of the HTTP client configuration as defined by
76+
* <a href="https://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport(includingSSLsupport)-UsingConfiguration">Apache CXF format</a>, required for SSL
77+
* settings</li>
7578
* </ul>
7679
*/
7780
public class CombinedXacmlAclAuthorizer extends SimpleAclAuthorizer
@@ -95,6 +98,13 @@ public class CombinedXacmlAclAuthorizer extends SimpleAclAuthorizer
9598
*/
9699
public static final String AUTHZ_CACHE_SIZE_MAX = "org.ow2.authzforce.kafka.pep.authz.cache.size.max";
97100

101+
/**
102+
* Name of Kafka configuration property specifying the location (URL supported by Spring {@link org.springframework.util.ResourceUtils}) of the HTTP client configuration as defined by
103+
* <a href="https://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport(includingSSLsupport)-UsingConfiguration">Apache CXF format</a>, required for SSL
104+
* settings
105+
*/
106+
public static final String HTTP_CLIENT_CFG_LOCATION = "org.ow2.authzforce.kafka.pep.http.client.cfg.location";
107+
98108
private static final int MAX_JSON_STRING_LENGTH = 1000;
99109

100110
private interface AuthzDecisionEvaluator
@@ -137,9 +147,24 @@ public void configure(final Map<String, ?> authorizerProperties)
137147
final String xacmlPdpUrlStr = (String) xacmlPdpUrlObj;
138148
LOGGER.debug("XACML PDP URL set from authorizer configuration property '{}': {}", XACML_PDP_URL_CFG_PROPERTY_NAME, xacmlPdpUrlStr);
139149

150+
final Object cxfHttpClientCfgLocationObj = authorizerProperties.get(HTTP_CLIENT_CFG_LOCATION);
151+
if (cxfHttpClientCfgLocationObj == null)
152+
{
153+
LOGGER.info("Configuration property '{}' undefined -> using default CXF HTTP client configuration", HTTP_CLIENT_CFG_LOCATION);
154+
return;
155+
}
156+
157+
if (!(cxfHttpClientCfgLocationObj instanceof String))
158+
{
159+
throw new IllegalArgumentException(this + ": authorizer configuration property '" + HTTP_CLIENT_CFG_LOCATION + "' is not a String");
160+
}
161+
162+
final String cxfHttpClientCfgLocation = (String) cxfHttpClientCfgLocationObj;
163+
LOGGER.debug("Location of HTTP client configuration (Apache CXF format) set from authorizer configuration property '{}': {}", HTTP_CLIENT_CFG_LOCATION, cxfHttpClientCfgLocation);
164+
140165
pdpClient = WebClient
141166
.create(xacmlPdpUrlStr, Collections.singletonList(new JsonRiJaxrsProvider(/* extra parameters */)),
142-
LOGGER.isDebugEnabled() ? Collections.singletonList(new LoggingFeature()) : Collections.<Feature>emptyList(), null /* clientConfClasspathLocation */)
167+
LOGGER.isDebugEnabled() ? Collections.singletonList(new LoggingFeature()) : Collections.<Feature>emptyList(), cxfHttpClientCfgLocation)
143168
.type(XACML_JSON_MEDIA_TYPE).accept(XACML_JSON_MEDIA_TYPE);
144169

145170
final Object xacmlReqTmplObj = authorizerProperties.get(XACML_REQUEST_TEMPLATE_LOCATION_CFG_PROPERTY_NAME);
@@ -263,7 +288,7 @@ public void configure(final Map<String, ?> authorizerProperties)
263288

264289
private boolean evalAuthzDecision(final Session session, final Operation operation, final Resource resource, final Map<String, Object> authzAttributes)
265290
{
266-
LOGGER.error("Calling SimpleAclAuthorizer: session={}, operation={}, resource={}", session, operation, resource);
291+
LOGGER.debug("Calling SimpleAclAuthorizer: session={}, operation={}, resource={}", session, operation, resource);
267292

268293
final boolean simpleAclAuthorized = super.authorize(session, operation, resource);
269294

@@ -314,7 +339,7 @@ public boolean authorize(final Session session, final Operation operation, final
314339
*/
315340
final Map<String, Object> azAttributes = ImmutableMap.of("clientHost", session.clientAddress(), "principal", session.principal(), "operation", operation.toJava(), "resourceType",
316341
resource.resourceType().toJava(), "resourceName", resource.name());
317-
LOGGER.error("Authorizing access request: {}", azAttributes);
342+
LOGGER.debug("Authorizing access request: {}", azAttributes);
318343
final boolean isAuthorized = this.decisionEvaluator.eval(session, operation, resource, azAttributes);
319344
LOGGER.debug("isAuthorized (true iff Permit) = {}", isAuthorized);
320345
return isAuthorized;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.apache.cxf.common.logging.Slf4jLogger

src/test/ca.p12

4.15 KB
Binary file not shown.

src/test/java/org/ow2/authzforce/kafka/pep/test/CombinedXacmlAclAutorizerTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public class CombinedXacmlAclAutorizerTest
7272

7373
private static final Map<ResourceType, Set<AclOperation>> OPS_BY_RESOURCE_TYPE = ImmutableMap.of(
7474
//
75-
ResourceType.CLUSTER, ImmutableSet.of(AclOperation.ALTER, AclOperation.CLUSTER_ACTION, AclOperation.CREATE, AclOperation.DESCRIBE, AclOperation.IDEMPOTENT_WRITE),
75+
ResourceType.CLUSTER, ImmutableSet.of(AclOperation.ALTER, /* AclOperation.CLUSTER_ACTION, AclOperation.CREATE, */ AclOperation.DESCRIBE, AclOperation.IDEMPOTENT_WRITE),
7676
//
7777
ResourceType.GROUP, ImmutableSet.of(AclOperation.READ, AclOperation.DESCRIBE, AclOperation.DELETE),
7878
//
@@ -129,8 +129,8 @@ public CombinedXacmlAclAutorizerTest(final long authzCacheMaxSize) throws Unknow
129129
public void setUp() throws IOException
130130
{
131131
authorizer.configure(ImmutableMap.of(KafkaConfig.ZkConnectProp(), SHARED_ZOOKEEPER_TEST_RESOURCE.getZookeeperConnectString(), CombinedXacmlAclAuthorizer.XACML_PDP_URL_CFG_PROPERTY_NAME,
132-
"http://localhost:" + port + "/services/authz/pdp", CombinedXacmlAclAuthorizer.XACML_REQUEST_TEMPLATE_LOCATION_CFG_PROPERTY_NAME, XACML_REQ_TMPL_LOCATION,
133-
CombinedXacmlAclAuthorizer.AUTHZ_CACHE_SIZE_MAX, Long.toString(authzCacheMaxSize, 10)));
132+
"https://localhost:" + port + "/services/authz/pdp", CombinedXacmlAclAuthorizer.XACML_REQUEST_TEMPLATE_LOCATION_CFG_PROPERTY_NAME, XACML_REQ_TMPL_LOCATION,
133+
CombinedXacmlAclAuthorizer.HTTP_CLIENT_CFG_LOCATION, "file:src/test/resources/http-client.xml", CombinedXacmlAclAuthorizer.AUTHZ_CACHE_SIZE_MAX, Long.toString(authzCacheMaxSize, 10)));
134134
}
135135

136136
private void testAuthorizationForAllResourcesAndOperations(final String username, final boolean expectedAuthorized)
+20-3
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
11
cfg.dir=target/test-classes/authz-server
2+
3+
# Active profile
4+
spring.profiles.active=ssl
5+
26
# Server HTTP port
37
# Default server.port = 8080
48
# For HTTPS (for production, you should change keypairs and passwords)
59
#server.port=8443
610
# If server.ssl.enabled=true, make sure sec:http/sec:intercept-url/@requires-channel = 'https' in spring-beans.xml
7-
server.ssl.enabled=false
11+
server.ssl.enabled=true
812
server.ssl.key-store=file\:${cfg.dir}/server.p12
913
server.ssl.key-store-type=PKCS12
1014
server.ssl.key-store-password=changeit
1115
server.ssl.key-alias=server
1216
server.ssl.key-password=changeit
13-
server.ssl.client-auth=
17+
server.ssl.trust-store: file\:${cfg.dir}/truststore.jks
18+
server.ssl.trust-store-password: changeit
19+
server.ssl.trust-store-type: JKS
20+
server.ssl.client-auth=need
1421

1522
# JAX-RS server endpoint address (default is "/")
16-
#cxf.jaxrs.server.path=/
23+
# cxf.jaxrs.server.path=/
1724
# Do not use server.address to set service endpoint address as it is already used by Spring Boot
1825
spring.beans.conf=file\:${cfg.dir}/spring-beans.xml
1926

27+
# Disable as much DispatcherServlet features we don't need as possible
28+
spring.mvc.dispatch-trace-request: false
29+
spring.mvc.dispatch-options-request: false
30+
spring.mvc.favicon.enabled: false # Whether to enable resolution of favicon.ico.
31+
spring.mvc.formcontent.putfilter.enabled: false
32+
spring.mvc.pathmatch.use-suffix-pattern: false
33+
spring.mvc.servlet.load-on-startup: -1
34+
spring.mvc.throw-exception-if-no-handler-found: true
35+
spring.mvc.log-resolved-exception: true
36+
2037
# LOGGING
2138
logging.config=file\:${cfg.dir}/logback.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
{
2+
"policy": {
3+
"id": "resource.type=CLUSTER",
4+
"version": "1.0",
5+
"target": [
6+
[
7+
[
8+
{
9+
"matchFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal",
10+
"value": "CLUSTER",
11+
"attributeDesignator": {
12+
"category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
13+
"id": "urn:thalesgroup:xacml:resource:resource-type",
14+
"dataType": "http://www.w3.org/2001/XMLSchema#string",
15+
"mustBePresent": true
16+
}
17+
}
18+
]
19+
]
20+
],
21+
"combiningAlgId": "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable",
22+
"policies": [
23+
{
24+
"policy": {
25+
"description": "Anonymous access to cluster kafka-cluster",
26+
"id": "resource.type=CLUSTER#resource.id=kafka-cluster",
27+
"version": "1.0",
28+
"target": [
29+
[
30+
[
31+
{
32+
"matchFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal",
33+
"value": "kafka-cluster",
34+
"attributeDesignator": {
35+
"category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
36+
"id": "urn:oasis:names:tc:xacml:1.0:resource:resource-id",
37+
"dataType": "http://www.w3.org/2001/XMLSchema#string",
38+
"mustBePresent": true
39+
}
40+
}
41+
]
42+
]
43+
],
44+
"combiningAlgId": "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable",
45+
"rules": [
46+
{
47+
"id": "action.id={CLUSTER_ACTION,CREATE}",
48+
"effect": "Permit",
49+
"target": [
50+
[
51+
[
52+
{
53+
"matchFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal",
54+
"value": "CLUSTER_ACTION",
55+
"attributeDesignator": {
56+
"category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action",
57+
"id": "urn:oasis:names:tc:xacml:1.0:action:action-id",
58+
"dataType": "http://www.w3.org/2001/XMLSchema#string",
59+
"mustBePresent": true
60+
}
61+
}
62+
],
63+
[
64+
{
65+
"matchFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal",
66+
"value": "CREATE",
67+
"attributeDesignator": {
68+
"category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action",
69+
"id": "urn:oasis:names:tc:xacml:1.0:action:action-id",
70+
"dataType": "http://www.w3.org/2001/XMLSchema#string",
71+
"mustBePresent": true
72+
}
73+
}
74+
]
75+
]
76+
]
77+
}
78+
]
79+
}
80+
}
81+
]
82+
}
83+
}

src/test/resources/authz-server/policies/resource.type=GROUP/1.0.xacml.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"combiningAlgId": "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable",
4545
"rules": [
4646
{
47-
"id": "action.id=READ",
47+
"id": "action.id={READ,DESCRIBE}",
4848
"effect": "Permit",
4949
"target": [
5050
[
@@ -59,6 +59,18 @@
5959
"mustBePresent": true
6060
}
6161
}
62+
],
63+
[
64+
{
65+
"matchFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal",
66+
"value": "DESCRIBE",
67+
"attributeDesignator": {
68+
"category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action",
69+
"id": "urn:oasis:names:tc:xacml:1.0:action:action-id",
70+
"dataType": "http://www.w3.org/2001/XMLSchema#string",
71+
"mustBePresent": true
72+
}
73+
}
6274
]
6375
]
6476
]

0 commit comments

Comments
 (0)