Commit 29b9edea authored by Romain Ferrari's avatar Romain Ferrari

Audit logs added. Marshal to json so it can be parsed easily by

logstash.
parent 3138adf5
......@@ -5,7 +5,7 @@
<groupId>com.thalesgroup.authzforce</groupId>
<artifactId>authzforce-parent</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>../authzforce/pom.xml</relativePath>
<relativePath>../authzforce/pom.xml</relativePath>
</parent>
<groupId>com.thalesgroup.authzforce.core</groupId>
<artifactId>authzforce-core</artifactId>
......@@ -20,6 +20,7 @@
<description>An authorization server that supports XACML, X.509 attributes certificates, SQL and LDAP</description>
<inceptionYear>2011</inceptionYear>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<copyrightOwner>Thales Services - ThereSIS</copyrightOwner>
<jdk.source>1.7</jdk.source>
<jdk.target>1.7</jdk.target>
......@@ -41,8 +42,18 @@
<dependency>
<groupId>com.thalesgroup.authzforce.core</groupId>
<artifactId>authzforce-model</artifactId>
<version>3.2.2</version>
</dependency>
<!-- /Authzforce dependencies -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
......@@ -62,12 +73,12 @@
</dependency>
<!-- Test dependencies -->
<!-- FIXME: Dependency no longer used. Remove it? -->
<!-- <dependency> -->
<!-- <groupId>org.jvnet.jaxb2_commons</groupId> -->
<!-- <artifactId>testing</artifactId> -->
<!-- <version>0.4.1.5</version> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.jvnet.jaxb2_commons</groupId> -->
<!-- <artifactId>testing</artifactId> -->
<!-- <version>0.4.1.5</version> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
<dependency>
<groupId>commons-jxpath</groupId>
<artifactId>commons-jxpath</artifactId>
......@@ -80,6 +91,7 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- /Test dependencies -->
<!-- Uncoment dependency below to use log4j as SLFJ implementation for test logs -->
<dependency>
<groupId>org.slf4j</groupId>
......@@ -92,8 +104,7 @@
<!-- <artifactId>logback-classic</artifactId> -->
<!-- <version>1.0.7</version> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
<!-- /Test dependencies -->
<!-- </dependency> -->
</dependencies>
<build>
<plugins>
......@@ -284,6 +295,51 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<debug>true</debug>
<verbose>true</verbose>
<extension>true</extension>
<args>
<arg>-Xannotate</arg>
<args>-Xequals</args>
<args>-XhashCode</args>
</args>
<episodes>
<episode>
<groupId>com.thalesgroup.ktd.scis</groupId>
<artifactId>oasis-xacml-model</artifactId>
</episode>
</episodes>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>0.6.4</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.4</version>
</plugin>
<plugin>
<groupId>com.thalesgroup.ktd.scis</groupId>
<artifactId>oasis-xacml-model</artifactId>
</plugin>
</plugins>
<catalog>src/main/resources/catalog.xml</catalog>
<catalogResolver>org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver</catalogResolver>
</configuration>
</plugin>
</plugins>
</build>
</project>
/**
* Copyright (C) 2011-2013 Thales Services - ThereSIS - All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thalesgroup.authzforce.audit;
import java.io.IOException;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.xacml.PolicySet;
import com.sun.xacml.Rule;
import com.sun.xacml.ctx.Result;
import com.sun.xacml.finder.AttributeFinderModule;
import com.sun.xacml.xacmlv3.Policy;
import com.thalesgroup.authzforce.BindingUtility;
public class AuditLog {
private static final String SEPARATOR = " ";
private static final String ELT_SEPARATOR = " ";
private static final String START_COLLECTION = "[ ";
private static final Object END_COLLECTION = " ]";
private static final Logger LOGGER = LoggerFactory
.getLogger(AuditLog.class);
protected String id;
protected String date;
protected Request request;
protected List<Policy> matchPolicies;
protected LinkedList<Result> resultPolicies;
protected List<PolicySet> matchPolicieSet;
protected LinkedList<Rule> rules;
protected LinkedList<Result> resultRule;
protected List<AttributesResolved> attrResolv;
public AuditLog() {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS");
date = dateFormat.format(new Date());
rules = new LinkedList<Rule>();
resultRule = new LinkedList<Result>();
matchPolicies = new LinkedList<Policy>();
resultPolicies = new LinkedList<Result>();
matchPolicieSet = new LinkedList<PolicySet>();
attrResolv = new LinkedList<AttributesResolved>();
}
public String getId() {
return id;
}
/**
* This should only be called by the AuditsLog class since the ID MUST be
* unique and fixed by a higher class
*
* @param id
*/
public void setId(String id) {
this.id = id;
}
public Request getRequest() {
return request;
}
public void setRequest(Request request) {
this.request = request;
}
public List<Rule> getRules() {
return rules;
}
public void addRule(Rule rule) {
this.rules.add(rule);
}
/**
* @return the resultRule
*/
protected LinkedList<Result> getResultRule() {
return resultRule;
}
/**
* @param resultRule
* the resultRule to set
*/
public void addResultRule(Result resultRule) {
this.resultRule.add(resultRule);
}
public String getDate() {
return date.toString();
}
public List<Policy> getMatchPolicies() {
return matchPolicies;
}
public void addMatchPolicies(Policy matchPolicy) {
this.matchPolicies.add(matchPolicy);
}
public void addResultMatchPolicy(Result result) {
resultPolicies.add(result);
}
/**
* @return the resultMatchPolicies
*/
protected LinkedList<Result> getResultMatchPolicy() {
return resultPolicies;
}
public List<AttributesResolved> getAttrResolv() {
return attrResolv;
}
public void setAttrResolv(List<AttributesResolved> attrResolv) {
this.attrResolv = attrResolv;
}
public String print() {
StringBuilder sb = new StringBuilder();
sb.append(this.getId() + ELT_SEPARATOR);
sb.append(this.getDate() + ELT_SEPARATOR);
sb.append(request2String(this.getRequest()) + ELT_SEPARATOR);
if (this.getMatchPolicies().size() > 0) {
int i = 0;
sb.append(START_COLLECTION);
for (Policy policy : this.getMatchPolicies()) {
// We fetch the string after "rule-combining-algorithm:" in
// order to display only
// the algorithm
String ruleCombAlg = policy.getRuleCombiningAlgId().substring(
policy.getRuleCombiningAlgId().indexOf(
"rule-combining-algorithm")
+ "rule-combining-algorithm:".length());
sb.append(policy.getPolicyId()
+ SEPARATOR
+ ruleCombAlg
+ SEPARATOR
+ ((Result) this.getResultMatchPolicy().get(i))
.getDecision() + SEPARATOR);
i++;
}
sb.append(END_COLLECTION);
}
if (this.getRules().size() > 0) {
sb.append(ELT_SEPARATOR);
sb.append(START_COLLECTION);
int i = 0;
for (Rule rule : this.getRules()) {
sb.append(rule.getRuleId() + SEPARATOR
+ ((Result) this.getResultRule().get(i)).getDecision()
+ SEPARATOR);
i++;
}
sb.append(END_COLLECTION);
}
if (this.getAttrResolv().size() > 0) {
sb.append(ELT_SEPARATOR);
sb.append(START_COLLECTION);
for (AttributesResolved attrResolved : this.getAttrResolv()) {
sb.append(attrResolved.getAttributeId() + SEPARATOR
+ attrResolved.getAttributeValue().getContent()
+ SEPARATOR);
}
sb.append(END_COLLECTION);
}
return sb.toString();
}
private String request2String(Request request) {
String result = null;
final StringWriter sw = new StringWriter();
try {
// Marshaller u =
// BindingUtility.XACML3_0_JAXB_CONTEXT.createMarshaller();
// u.marshal(request, sw);
JAXBContext.newInstance(Request.class).createMarshaller()
.marshal(request, sw);
result = sw.toString();
} catch (Exception e) {
LOGGER.error("Error marshalling Request", e);
} finally {
try {
sw.close();
} catch (IOException e) {
LOGGER.error(
"Error closing StringWriter for marshalling Request", e);
}
}
return result;
}
public void addAttrResolved(AttributeFinderModule attributeFinderModule) {
System.out.println("addAttrResolved");
}
}
......@@ -15,113 +15,123 @@
*/
package com.thalesgroup.authzforce.audit;
import java.io.IOException;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.xacml.Rule;
import com.sun.xacml.xacmlv3.Policy;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditedPolicy;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditedRule;
/**
* Audit logging class
*
* Note: to disable audit logging, just change log level for logger named
* 'com.thalesgroup.authzforce.audit.AuditLogs' in the SLF4J logger configuration file. Use level <=
* INFO to enable, level > INFO to disable. Other options on this logger may be configured in the
* logging configuration file to customize audit logging.
* 'com.thalesgroup.authzforce.audit.AuditLogs' in the SLF4J logger
* configuration file. Use level <= INFO to enable, level > INFO to disable.
* Other options on this logger may be configured in the logging configuration
* file to customize audit logging.
*
*/
public final class AuditLogs
{
public final class AuditLogs {
/**
* Logger used for all classes
*/
private static final Logger LOGGER = LoggerFactory.getLogger(AuditLogs.class);
private static final Logger LOGGER = LoggerFactory
.getLogger(AuditLogs.class);
private static final String HASH_ALG = "MD5";
protected static volatile AuditLogs INSTANCE;
protected static HashMap<String, AuditLog> audits;
private AuditLogs()
{
audits = new HashMap<String, AuditLog>();
protected static HashMap<String, com.thalesgroup.authzforce.audit.schema.pdp.AuditLog> audits;
private AuditLogs() {
audits = new HashMap<String, com.thalesgroup.authzforce.audit.schema.pdp.AuditLog>();
}
public synchronized static AuditLogs getInstance()
{
if (INSTANCE == null)
{
public synchronized static AuditLogs getInstance() {
if (INSTANCE == null) {
INSTANCE = new AuditLogs();
}
return INSTANCE;
}
public synchronized static AuditLogs remove()
{
if (INSTANCE != null)
{
public synchronized static AuditLogs remove() {
if (INSTANCE != null) {
INSTANCE = new AuditLogs();
}
return INSTANCE;
}
public synchronized static Map<String, AuditLog> getAudits()
{
public synchronized static Map<String, com.thalesgroup.authzforce.audit.schema.pdp.AuditLog> getAudits() {
return audits;
}
public synchronized static void clearAudits() {
audits.clear();
}
public synchronized static void addAudit(AuditLog audit)
{
// BASE64Encoder enc = new sun.misc.BASE64Encoder();
// String toEncode = audit.getRequest().toString() + audit.getDate();
// String base64 = enc.encode(toEncode.getBytes());
if (audits == null)
{
audits = new HashMap<String, AuditLog>();
public synchronized static void addAudit(
com.thalesgroup.authzforce.audit.schema.pdp.AuditLog audit) {
if (audits == null) {
audits = new HashMap<String, com.thalesgroup.authzforce.audit.schema.pdp.AuditLog>();
}
audit.setId(String.valueOf(audit.getRequest().hashCode()));
if (audits.containsKey(audit.getId()))
{
try {
MessageDigest digest = MessageDigest.getInstance(HASH_ALG);
byte[] hash = digest
.digest(String.valueOf(
audit.getDate() + audit.getRequest().hashCode())
.getBytes());
String id = byte2String(hash);
audit.setId(id);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
if (audits.containsKey(audit.getId())) {
audits.put(audit.getId(), updateAudit(audit));
} else
{
} else {
audits.put(audit.getId(), audit);
}
}
private static AuditLog updateAudit(AuditLog newAudit)
{
AuditLog updatedAudit = audits.get(newAudit.getId());
private static com.thalesgroup.authzforce.audit.schema.pdp.AuditLog updateAudit(
com.thalesgroup.authzforce.audit.schema.pdp.AuditLog newAudit) {
com.thalesgroup.authzforce.audit.schema.pdp.AuditLog updatedAudit = audits
.get(newAudit.getId());
// Updating rules and decision for rules
if (newAudit.getRules().size() > 0)
{
if (newAudit.getRules().size() > 0) {
int i = 0;
for (Rule ruleElt : newAudit.getRules())
{
for (AuditedRule ruleElt : newAudit.getRules()) {
// We don't want any doublon. TODO: Maybe use a set ?
if (!updatedAudit.getRules().contains(ruleElt))
{
updatedAudit.addRule(ruleElt);
if (!updatedAudit.getRules().contains(ruleElt)) {
updatedAudit.getRules().add(ruleElt);
// If we've got a rule, we've got a decision
updatedAudit.addResultRule(newAudit.getResultRule().get(i));
// updatedAudit.getResultRules().add(newAudit.getResultRules().get(i));
}
i++;
}
}
if (newAudit.getMatchPolicies().size() > 0)
{
if (newAudit.getMatchedPolicies().size() > 0) {
int i = 0;
for (Policy policyElt : newAudit.getMatchPolicies())
{
for (AuditedPolicy policyElt : newAudit.getMatchedPolicies()) {
// We don't want any doublon. TODO: Maybe use a set ?
if (!updatedAudit.getMatchPolicies().contains(policyElt))
{
updatedAudit.addMatchPolicies(policyElt);
if (!updatedAudit.getMatchedPolicies().contains(policyElt)) {
updatedAudit.getMatchedPolicies().add(policyElt);
// If we've got a rule, we've got a decision
updatedAudit.addResultMatchPolicy(newAudit.getResultMatchPolicy().get(i));
// updatedAudit.getResultPolicies().add(newAudit.getResultPolicies().get(i));
}
i++;
}
......@@ -131,32 +141,49 @@ public final class AuditLogs
}
/**
* One part of the method needs to be synchronized as it modify the map containing the audits
* logs. No one should update this map while it's being displayed and cleared.
* One part of the method needs to be synchronized as it modify the map
* containing the audits logs. No one should update this map while it's
* being displayed and cleared.
*/
public void print()
{
Map<String, AuditLog> auditTmp = null;
synchronized (audits)
{
auditTmp = new HashMap<String, AuditLog>(audits);
audits.clear();
@Override
public String toString() {
StringWriter sw = new StringWriter();
try {
for (String hash : getAudits().keySet()) {
// JAXBContext.newInstance(AuditLog.class).createMarshaller().marshal(getAudits().get(hash),
// sw);
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
// make serializer use JAXB annotations (only)
mapper.getSerializationConfig().withAnnotationIntrospector(
introspector);
mapper.writeValue(sw, getAudits().get(hash));
}
} catch (JsonGenerationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (AuditLog auditElt : auditTmp.values())
{
StringBuilder sb = new StringBuilder();
sb.append(auditElt.print());
/**
* To disable audit logging at this point, just change log level for logger named
* 'com.thalesgroup.authzforce.audit.AuditLogs' in the SLF4J logger configuration Use
* level <= INFO to enable, level > INFO to disable.
*/
LOGGER.info(sb.toString());
clearAudits();
return sw.toString();
}
private static String byte2String(byte[] hash) {
StringBuffer id = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
if ((0xff & hash[i]) < 0x10) {
id.append("0" + Integer.toHexString((0xFF & hash[i])));
} else {
id.append(Integer.toHexString(0xFF & hash[i]));
}
}
// Releasing memory
auditTmp = null;
// System.out.println(sb);
return id.toString();
}
}
......@@ -15,6 +15,20 @@
*/
package com.thalesgroup.authzforce.audit.aspect;
import java.io.StringWriter;
import java.net.URI;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Attribute;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Policy;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Result;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Rule;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
......@@ -23,19 +37,28 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.xacml.BasicEvaluationCtx;
import com.sun.xacml.Rule;
import com.sun.xacml.attr.DateTimeAttribute;
import com.sun.xacml.attr.xacmlv3.AttributeValue;
import com.sun.xacml.cond.xacmlv3.EvaluationResult;
import com.sun.xacml.ctx.Result;
import com.sun.xacml.xacmlv3.Policy;
import com.thalesgroup.authzforce.audit.AttributesResolved;
import com.thalesgroup.authzforce.audit.AuditLog;
import com.thalesgroup.authzforce.audit.AuditLogs;
import com.thalesgroup.authzforce.audit.annotations.Audit;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditLog;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditedPolicy;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditedResult;
import com.thalesgroup.authzforce.audit.schema.pdp.AuditedRule;
import com.thalesgroup.authzforce.xacml.schema.XACMLAttributeId;
import com.thalesgroup.authzforce.xacml.schema.XACMLDatatypes;
@Aspect
public class AuditAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(AuditAspect.class);
private static final Logger LOGGER = LoggerFactory
.getLogger(AuditAspect.class);
private static final DateFormat dateFormat = new SimpleDateFormat(
"dd-MM-yyyy HH:mm:ss.SSSSSSSSS");
private static final DateFormat dateFormatWOoNano = new SimpleDateFormat(
"dd-MM-yyyy HH:mm:ss");
@Pointcut("execution (@com.thalesgroup.authzforce.audit.annotations * *.*(..))")
public void searchAnnotation() {
......@@ -47,25 +70,41 @@ public class AuditAspect {
switch (annotation.type()) {
case RULE:
AuditLog audit = new AuditLog();
audit.addRule((Rule) jp.getTarget());
audit.addResultRule((Result) result);
AuditedRule auditedRule = new AuditedRule();
auditedRule.setId(((Rule) jp.getTarget()).getRuleId());
auditedRule.setResult(AuditedResult.fromValue(((Result) result)
.getDecision().value()));
for (Object arg : jp.getArgs()) {
if (arg instanceof BasicEvaluationCtx) {
audit.setDate(this.formatDate(((BasicEvaluationCtx) arg)
.getCurrentDateTime()));
audit.setRequest(((BasicEvaluationCtx) arg).getRequest());
audit = this.setAttributes(audit, ((BasicEvaluationCtx) arg));
}
}
audit.getRules().add(auditedRule);
AuditLogs.getInstance().addAudit(audit);
break;
case POLICY:
audit = new AuditLog();
audit.addMatchPolicies((Policy) jp.getTarget());
audit.addResultMatchPolicy((Result) result);
AuditedPolicy auditedPolicy = new AuditedPolicy();
auditedPolicy.setId(((Policy) jp.getTarget()).getPolicyId());
auditedPolicy.setRuleCombiningAlgorithm(((Policy) jp.getTarget())
.getRuleCombiningAlgId());
auditedPolicy.setResult(AuditedResult.fromValue(((Result) result)
.getDecision().value()));
for (Object arg : jp.getArgs()) {
if (arg instanceof BasicEvaluationCtx) {
audit.setDate(this.formatDate(((BasicEvaluationCtx) arg)
.getCurrentDateTime()));
audit.setRequest(((BasicEvaluationCtx) arg).getRequest());
audit = this.setAttributes(audit, ((BasicEvaluationCtx) arg));;
}
}
audit.getMatchedPolicies().add(auditedPolicy);
AuditLogs.getInstance().addAudit(audit);
break;