Skip to content

Commit

Permalink
Adding mutual SSL support
Browse files Browse the repository at this point in the history
  • Loading branch information
rnavagamuwa committed Mar 19, 2019
1 parent a2ba824 commit 93761b1
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 16 deletions.
6 changes: 5 additions & 1 deletion sample/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
spring.thymeleaf.cache=false
#logging.level.web=debug
xacml.pdp.url=https://localhost:9443/api/identity/entitlement/decision/pdp
xacml.pdp.url=https://localhost:9443/api/identity/entitlement/decision/pdp
xacml.pdp.trustStore=truststore
xacml.pdp.trustStore.password=password
xacml.pdp.keyStore=keystore
xacml.pdp.keyStore.password=password
Binary file added sample/src/main/resources/keystore
Binary file not shown.
Binary file added sample/src/main/resources/truststore
Binary file not shown.
5 changes: 5 additions & 0 deletions sdk/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
<artifactId>ehcache</artifactId>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>

</dependencies>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
package org.wso2.spring.security.abac;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;
import org.wso2.spring.security.abac.cache.CacheManager;
import org.wso2.spring.security.abac.cache.EhCacheManager;
import org.wso2.spring.security.abac.exception.AttributeEvaluatorException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.Collections;
import java.util.Properties;
import javax.net.ssl.SSLContext;

/**
* @author Randika Navagamuwa
Expand All @@ -22,14 +35,24 @@
public class XacmlAttributeHandler implements AttributeHandler {

private static String XACML_PDP_URL;
private CacheManager cacheManager;
private static String TRUST_STORE;
private static String TRUST_STORE_PASSWORD;
private static String KEY_STORE;
private static String KEY_STORE_PASSWORD;

private CacheManager responseCacheManager;
private SSLContext sslContext;

public XacmlAttributeHandler() {

try {
XACML_PDP_URL = PropertiesLoaderUtils
.loadAllProperties("application.properties")
.getProperty("xacml.pdp.url");
Properties properties = PropertiesLoaderUtils
.loadAllProperties("application.properties");
XACML_PDP_URL = properties.getProperty("xacml.pdp.url");
TRUST_STORE = properties.getProperty("xacml.pdp.trustStore");
TRUST_STORE_PASSWORD = properties.getProperty("xacml.pdp.trustStore.password");
KEY_STORE = properties.getProperty("xacml.pdp.keyStore");
KEY_STORE_PASSWORD = properties.getProperty("xacml.pdp.keyStore.password");
} catch (IOException e) {

//todo stop the whole app
Expand All @@ -40,30 +63,50 @@ public XacmlAttributeHandler() {
//todo stop the whole app
}

this.cacheManager = new EhCacheManager();
try {
this.sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(loadPfx("classpath:".concat(KEY_STORE), KEY_STORE_PASSWORD.toCharArray()),
KEY_STORE_PASSWORD.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile("classpath:".concat(TRUST_STORE)),
TRUST_STORE_PASSWORD.toCharArray())
.build();
} catch (Exception e) {

//todo stop the whole app
throw new AttributeEvaluatorException("Failed to read keystore or truststore", e);
}

this.responseCacheManager = new EhCacheManager();
}

@Override
public boolean authorize(String authRequest) {

String cachedResponse = this.cacheManager.get(authRequest);
String cachedResponse = this.responseCacheManager.get(authRequest);

if (cachedResponse == null) {
RestTemplate restTemplate = new RestTemplate();

HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();

RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder().requestFactory(() ->
new HttpComponentsClientHttpRequestFactory(client));
RestTemplate rt = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth("admin", "admin");
headers.set("WSO2-Identity-User", "admin");

HttpEntity<String> entity = new HttpEntity<>(authRequest, headers);

ResponseEntity response = restTemplate.postForEntity(XACML_PDP_URL, entity, String.class);
if (response.getBody() == null) {
ResponseEntity response = rt.postForEntity(XACML_PDP_URL, entity, String.class);
if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
return false;
}
cachedResponse = response.getBody().toString();
this.cacheManager.putIfAbsent(authRequest, cachedResponse);
this.responseCacheManager.putIfAbsent(authRequest, cachedResponse);
}

JSONObject responseObj = new JSONObject(cachedResponse);
Expand All @@ -82,4 +125,14 @@ public boolean authorize(String authRequest) {
return true;
}

private KeyStore loadPfx(String file, char[] password) throws Exception {

KeyStore keyStore = KeyStore.getInstance("JKS");
File key = ResourceUtils.getFile(file);
try (InputStream in = new FileInputStream(key)) {
keyStore.load(in, password);
}
return keyStore;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ public class EhCacheManager implements org.wso2.spring.security.abac.cache.Cache
private static long MAX_ENTRIES = 100;

private CacheManager cacheManager;
private Cache<String, String> responseCache;
private Cache<String, String> cache;

public EhCacheManager() {

cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
cacheManager.init();

responseCache = cacheManager.createCache(CACHE_NAME, CacheConfigurationBuilder
cache = cacheManager.createCache(CACHE_NAME, CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(MAX_ENTRIES))
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(EXPIRY_IN_MINUTUES)))
.build());
}

public String get(String cahceKey) {

return this.responseCache.get(cahceKey);
return this.cache.get(cahceKey);
}

public String putIfAbsent(String key, String value) {

return this.responseCache.putIfAbsent(key, value);
return this.cache.putIfAbsent(key, value);
}
}

0 comments on commit 93761b1

Please sign in to comment.