Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For creating client specific detection points #35

Merged
merged 5 commits into from
Feb 10, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.owasp.appsensor.analysis;

import java.util.Collection;

import java.util.ArrayList;
import javax.inject.Inject;
import javax.inject.Named;

Expand Down Expand Up @@ -52,57 +52,76 @@ public class ReferenceEventAnalysisEngine extends EventAnalysisEngine {
@Override
public void analyze(Event event) {

SearchCriteria criteria = new SearchCriteria().
setUser(event.getUser()).
setDetectionPoint(event.getDetectionPoint()).
setDetectionSystemIds(appSensorServer.getConfiguration().getRelatedDetectionSystems(event.getDetectionSystem()));

// find all events matching this event for this user
Collection<Event> existingEvents = appSensorServer.getEventStore().findEvents(criteria);

Collection<DetectionPoint> configuredDetectionPoints = appSensorServer.getConfiguration().findDetectionPoints(event.getDetectionPoint());

if (configuredDetectionPoints.size() > 0) {

for(DetectionPoint configuredDetectionPoint : configuredDetectionPoints) {

// filter and count events that match this detection point (filtering by threshold)
// and that are after the most recent attack (filter by timestamp)
int eventCount = countEvents(existingEvents, event, configuredDetectionPoint);

// if the event count is 0, reset to 1 -> we know at least 1 event has occurred (the one we're considering)
// this can occur sometimes when testing with dates out of the given range or due to clock drift
if (eventCount == 0) {
eventCount = 1;
}

// examples for the below code
// 1. count is 5, t.count is 10 (5%10 = 5, No Violation)
// 2. count is 45, t.count is 10 (45%10 = 5, No Violation)
// 3. count is 10, t.count is 10 (10%10 = 0, Violation Observed)
// 4. count is 30, t.count is 10 (30%10 = 0, Violation Observed)

int thresholdCount = configuredDetectionPoint.getThreshold().getCount();
Collection<DetectionPoint> configuredDetectionPoints = null;

if (eventCount % thresholdCount == 0) {
logger.info("Violation Observed for user <" + event.getUser().getUsername() + "> - storing attack");
//check if the client has custom detection points
if(appSensorServer.getConfiguration().findCustomDectectionClientName(event.getDetectionSystem().getDetectionSystemId())){
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shreyasdn I think this section (this if-else block) is actually un-necessary. If you make the changes I suggested below about the findDetectionPoints methods I think you should be fine without making any changes here EXCEPT you need to pass in the detection system id as the additional parameter as you've done below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here i wanted to avoid having two loops instead of one hence the call. Much more efficient with a get on a map and a loop instead of two loops would you agree?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that's absolutely more efficient, but it does complicate the code a bit. I don't think it'll be that much of a performance hit with the simpler code, but if it is, we can always cache the data in the ServerConfiguration object. That way it'll be super fast for doing a lookup.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok will make those changes and resubmit by tonight.

configuredDetectionPoints = appSensorServer.getConfiguration().findDetectionPoints(event.getDetectionPoint(),event.getDetectionSystem().getDetectionSystemId());
if (configuredDetectionPoints.size() > 0) {
addDetectedEvents(configuredDetectionPoints,event);
}else{
logger.error("Could not find detection point configured for this type: " + event.getDetectionPoint().getLabel());
}
}else{
configuredDetectionPoints = appSensorServer.getConfiguration().findDetectionPoints(event.getDetectionPoint());
System.out.println("here in false");
if(configuredDetectionPoints.size() > 0){
addDetectedEvents(configuredDetectionPoints,event);
}else{
logger.error("Could not find detection point configured for this type: " + event.getDetectionPoint().getLabel());
}
}
}

private void addDetectedEvents(Collection<DetectionPoint> detectionPoints,Event event){

SearchCriteria criteria = new SearchCriteria().
setUser(event.getUser()).
setDetectionPoint(event.getDetectionPoint()).
setDetectionSystemIds(appSensorServer.getConfiguration().getRelatedDetectionSystems(event.getDetectionSystem()));

// find all events matching this event for this user
Collection<Event> existingEvents = appSensorServer.getEventStore().findEvents(criteria);

ArrayList<DetectionPoint> points = (ArrayList)detectionPoints;
for(DetectionPoint configuredDetectionPoint : points) {

// filter and count events that match this detection point (filtering by threshold)
// and that are after the most recent attack (filter by timestamp)
int eventCount = countEvents(existingEvents, event, configuredDetectionPoint);

//have determined this event triggers attack
//ensure appropriate detection point is being used (associated responses, etc.)
Attack attack = new Attack(
event.getUser(),
configuredDetectionPoint,
event.getTimestamp(),
event.getDetectionSystem(),
event.getResource()
);
// if the event count is 0, reset to 1 -> we know at least 1 event has occurred (the one we're considering)
// this can occur sometimes when testing with dates out of the given range or due to clock drift
if (eventCount == 0) {
eventCount = 1;
}

appSensorServer.getAttackStore().addAttack(attack);
// examples for the below code
// 1. count is 5, t.count is 10 (5%10 = 5, No Violation)
// 2. count is 45, t.count is 10 (45%10 = 5, No Violation)
// 3. count is 10, t.count is 10 (10%10 = 0, Violation Observed)
// 4. count is 30, t.count is 10 (30%10 = 0, Violation Observed)

int thresholdCount = configuredDetectionPoint.getThreshold().getCount();

if (eventCount % thresholdCount == 0) {
logger.info("Violation Observed for user <" + event.getUser().getUsername() + "> - storing attack");

//have determined this event triggers attack
//ensure appropriate detection point is being used (associated responses, etc.)
Attack attack = new Attack(
event.getUser(),
configuredDetectionPoint,
event.getTimestamp(),
event.getDetectionSystem(),
event.getResource()
);

appSensorServer.getAttackStore().addAttack(attack);
}
}
}
} else {
logger.error("Could not find detection point configured for this type: " + event.getDetectionPoint().getLabel());
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package org.owasp.appsensor.core.configuration.server;

import java.io.File;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.Transient;

Expand Down Expand Up @@ -48,8 +50,21 @@ public abstract class ServerConfiguration {

private String geolocationDatabasePath;

//Change for adding new custom client specific detection points
private HashMap<String,List<DetectionPoint>> customDetectionPoints = new HashMap<String, List<DetectionPoint>>();

private static transient Map<String, ClientApplication> clientApplicationCache = Collections.synchronizedMap(new HashMap<String, ClientApplication>());


public HashMap<String,List<DetectionPoint>> getCustomDetectionPoints() {
return customDetectionPoints;
}

public ServerConfiguration setCustomDetectionPoints(HashMap<String,List<DetectionPoint>> customPoints) {
this.customDetectionPoints = customPoints;
return this;
}

public File getConfigurationFile() {
return configurationFile;
}
Expand Down Expand Up @@ -179,7 +194,7 @@ public Collection<String> getRelatedDetectionSystems(DetectionSystem detectionSy
* @return DetectionPoint populated with configuration information from server-side config
*/
public Collection<DetectionPoint> findDetectionPoints(DetectionPoint search) {
Collection<DetectionPoint> matches = new ArrayList<>();
Collection<DetectionPoint> matches = new ArrayList<DetectionPoint>();

for (DetectionPoint configuredDetectionPoint : getDetectionPoints()) {
if (configuredDetectionPoint.typeMatches(search)) {
Expand All @@ -190,6 +205,47 @@ public Collection<DetectionPoint> findDetectionPoints(DetectionPoint search) {
return matches;
}

/**
* Locate matching client name in custom configuration from server-side config file.
*
* @param clientApplicationName the client name for which the detection point exists
*/
public Boolean findCustomDectectionClientName(String clientName){
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shreyasdn you should be able to delete this method altogether I think

if(getCustomDetectionPoints().size() != 0){
return getCustomDetectionPoints().containsKey(clientName);
}
return false;

}

/**
* Locate matching detection points configuration from server-side config file.
*
* @param search detection point that has been added to the system
* @param clientApplicationName the client name for which the detection point exists
* @return DetectionPoint populated with configuration information from server-side config
*/

public Collection<DetectionPoint> findDetectionPoints(DetectionPoint search, String clientApplicationName) {
Collection<DetectionPoint> matches = new ArrayList<DetectionPoint>();

for (Entry customDetectionPoint : getCustomDetectionPoints().entrySet()) {
String clientName = customDetectionPoint.getKey().toString();
if(clientApplicationName.equals(clientName)){
List<DetectionPoint> customList = (List<DetectionPoint>)customDetectionPoint.getValue();
for(DetectionPoint customPoint: customList)
{
if (customPoint.typeMatches(search)) {
matches.add(customPoint);
}
}
}


Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shreyasdn the way I would do this is keep 2 lists. The first list would have what you've already done in this method. The second list would come from calling the existing findDetectionPoints method. That would give you the "normal" detection points, and the "custom" detection points for this client in 2 different lists. I would then "merge" the 2 lists by adding all the "custom" detection points first. Then I would go through the "normal" detection points and add each one ONLY if it does not already exist. Let me know if this is unclear.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to avoid the two loops there hence the hasDetectionPoints method and the two separate findDetectionPoints method.

}
return matches;
}

public ClientApplication findClientApplication(String clientApplicationName) {
ClientApplication clientApplication = null;

Expand Down
27 changes: 27 additions & 0 deletions appsensor-core/src/main/resources/appsensor_server_config_2.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,38 @@
</xsd:sequence>
</xsd:complexType>







<xsd:complexType name="detection-points">
<xsd:sequence>
<xsd:element name="clients" type="asconfig:clients" minOccurs="0" maxOccurs="1" />
<xsd:element name="detection-point" type="asconfig:detection-point" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="clients">
<xsd:sequence>
<xsd:element name="client" type="asconfig:client" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="client">
<xsd:sequence>
<xsd:element name="client-name" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="custom-detection-point" type="asconfig:custom-detection-point" minOccurs="1" maxOccurs="unbounded" />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shreyasdn I don't think you need the "custom-detection-point" element at all. You can just use "detection-point" here and it should be fine. It should be clear that it's custom since it's nested within the "clients/client" elements.

</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="custom-detection-point">
<xsd:sequence>
<xsd:element name="detection-point" type="asconfig:detection-point" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>


<xsd:complexType name="interval">
<xsd:simpleContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLResolver;
Expand Down Expand Up @@ -173,6 +174,8 @@ private ServerConfiguration readServerConfiguration(XMLStreamReader xmlReader) t
configuration.getCorrelationSets().addAll(readCorrelationSets(xmlReader));
} else if("config:detection-point".equals(name)) {
configuration.getDetectionPoints().add(readDetectionPoint(xmlReader));
} else if("config:clients".equals(name)) {
configuration.getCustomDetectionPoints().putAll(readCustomDetectionPoints(xmlReader));
} else {
/** unexpected start element **/
}
Expand Down Expand Up @@ -316,6 +319,51 @@ private DetectionPoint readDetectionPoint(XMLStreamReader xmlReader) throws XMLS
return detectionPoint;
}

private HashMap<String,List<DetectionPoint>> readCustomDetectionPoints(XMLStreamReader xmlReader) throws XMLStreamException {
DetectionPoint detectionPoint = new DetectionPoint();
HashMap<String,List<DetectionPoint>> customPoints = new HashMap<String,List<DetectionPoint>>();
String clientName = "";
boolean finished = false;

while(!finished && xmlReader.hasNext()) {
int event = xmlReader.next();
String name = XmlUtils.getElementQualifiedName(xmlReader, namespaces);
List<DetectionPoint> customList = new ArrayList<DetectionPoint>();


switch(event) {
case XMLStreamConstants.START_ELEMENT:
if("config:client-name".equals(name)) {
clientName = xmlReader.getElementText().trim();
}else if("config:detection-point".equals(name)) {
customList.add(readDetectionPoint(xmlReader));

}else {
/** unexpected start element **/
}
break;
case XMLStreamConstants.END_ELEMENT:
if("config:clients".equals(name)) {
finished = true;
}else if("config:client".equals(name)) {
customPoints.put(clientName,customList);
customList = new ArrayList<DetectionPoint>();
}else {

/** unexpected end element **/
}
break;
default:
/** unused xml element - nothing to do **/
break;
}

//clientName = "";
}

return customPoints;
}

private Threshold readThreshold(XMLStreamReader xmlReader) throws XMLStreamException {
Threshold threshold = new Threshold();
boolean finished = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public void testConfigLoad() throws Exception {
assertEquals(3, configuration.getCorrelationSets().size());
assertEquals("server1", configuration.getCorrelationSets().iterator().next().getClientApplications().iterator().next());

assertEquals(1, configuration.getCustomDetectionPoints().size());
//assertEquals("server1", configuration.getCorrelationSets().iterator().next().getClientApplications().iterator().next());

assertEquals(5, configuration.getDetectionPoints().size());
assertEquals("IE1", configuration.getDetectionPoints().iterator().next().getLabel());
assertEquals(4, configuration.getDetectionPoints().iterator().next().getThreshold().getInterval().getDuration());
Expand Down
Loading