Skip to content

Commit

Permalink
Adding initial version of the sample
Browse files Browse the repository at this point in the history
  • Loading branch information
rnavagamuwa committed Mar 15, 2019
0 parents commit 9722754
Show file tree
Hide file tree
Showing 22 changed files with 703 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
88 changes: 88 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http:https://maven.apache.org/POM/4.0.0" xmlns:xsi="http:https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:https://maven.apache.org/POM/4.0.0 http:https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rnavagamuwa</groupId>
<artifactId>spring-security-abac</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-abac</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.7.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.rnavagamuwa.springsecurity;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
* @author Randika Navagamuwa
*/
@SpringBootApplication
public class SpringSecurityApplication {

@Bean
public BCryptPasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder();
}

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}

public static void main(String[] args) {

SpringApplication.run(SpringSecurityApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.rnavagamuwa.springsecurity.abac;

import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;

import java.io.Serializable;

/**
* @author Randika Navagamuwa
*/
public class AttributeEvaluator implements PermissionEvaluator {

private AuthRequestBuilder authRequestBuilder;
private AttributeHandler attributeHandler;

public AttributeEvaluator() {

this.authRequestBuilder = new XacmlAuthRequestBuilder();
this.attributeHandler = new XacmlAttributeHandler();
}

@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {

return this.attributeHandler.authorize(this.authRequestBuilder.
createAuthRequest(targetDomainObject.toString(), permission.toString()));
}

@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {

return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.rnavagamuwa.springsecurity.abac;

/**
* @author Randika Navagamuwa
*/
public interface AttributeHandler {

boolean authorize(String policyRequest);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.rnavagamuwa.springsecurity.abac;

/**
* @author Randika Navagamuwa
*/
public interface AuthRequestBuilder {

String createAuthRequest(String policyName, String jsonKeyValuePairs);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.rnavagamuwa.springsecurity.abac;

import com.rnavagamuwa.springsecurity.abac.cache.CacheManager;
import com.rnavagamuwa.springsecurity.abac.cache.EhCacheManager;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

/**
* @author Randika Navagamuwa
*/
@SuppressWarnings("WeakerAccess")
public class XacmlAttributeHandler implements AttributeHandler {

private static String XACML_PDP_URL = "https://localhost:9443/api/identity/entitlement/decision/pdp";
private CacheManager cacheManager;

public XacmlAttributeHandler() {

this.cacheManager = new EhCacheManager();
}

@Override
public boolean authorize(String authRequest) {

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

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

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth("admin", "admin");

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

ResponseEntity response = restTemplate.postForEntity(XACML_PDP_URL, entity, String.class);
if (response.getBody() == null) {
return false;
}
cachedResponse = response.getBody().toString();
this.cacheManager.putIfAbsent(authRequest, cachedResponse);
}

JSONObject responseObj = new JSONObject(cachedResponse);
JSONArray responseDataArr = responseObj.getJSONArray("Response");

if (responseDataArr.isEmpty()) {
return false;
}

for (Object Response : responseDataArr) {
JSONObject currentResponse = (JSONObject) Response;
if (!currentResponse.getString("Decision").equals("Permit")) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.rnavagamuwa.springsecurity.abac;

import com.rnavagamuwa.springsecurity.abac.exception.AttributeEvaluatorException;
import org.apache.commons.io.FileUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.json.JSONObject;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;

/**
* @author Randika Navagamuwa
*/
public class XacmlAuthRequestBuilder implements AuthRequestBuilder {

private static String ATTRIBUTE_CONFIG_FILE_NAME = "xacmlConfig.json";

@Override
public String createAuthRequest(String policyName, String jsonKeyValuePairs) {

VelocityContext vc = generateVelocityData(jsonKeyValuePairs);

String xacmlRequest;
try {
xacmlRequest = FileUtils.readFileToString(ResourceUtils.getFile("classpath:" + ATTRIBUTE_CONFIG_FILE_NAME),
StandardCharsets.UTF_8);

VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH,
ResourceUtils.getFile("classpath:" + ATTRIBUTE_CONFIG_FILE_NAME).getParent());
Template template = velocityEngine.getTemplate(ATTRIBUTE_CONFIG_FILE_NAME);
velocityEngine.init();

StringWriter writer = new StringWriter();
template.merge(vc, writer);

xacmlRequest = new JSONObject(writer.toString()).get(policyName).toString();

} catch (IOException e) {

throw new AttributeEvaluatorException("Failed to build the XACML Json request for policy with name : " +
policyName, e);
}

if (xacmlRequest == null || xacmlRequest.isEmpty()) {

throw new AttributeEvaluatorException("Generated XACML request is empty or NULL for policy with name : " +
policyName);
}

return xacmlRequest;
}

private VelocityContext generateVelocityData(String jsonKeyValuePairs) {

JSONObject jsonObject = new JSONObject(jsonKeyValuePairs.trim());

Iterator<String> keys = jsonObject.keys();

ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)
RequestContextHolder.currentRequestAttributes();
HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();

VelocityContext velocityContext = new VelocityContext();

while (keys.hasNext()) {
String key = keys.next();
String value = jsonObject.get(key).toString();
velocityContext.put(key, httpServletRequest.getHeader(value));
}

return velocityContext;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.rnavagamuwa.springsecurity.abac.cache;

/**
* @author Randika Navagamuwa
*/
public interface CacheManager {

String get(String cahceKey);

String putIfAbsent(String key, String value);
}
Loading

0 comments on commit 9722754

Please sign in to comment.