Wednesday, May 28, 2014

Saving encrypted password attribute in MongoDb using Spring

In my current project I'm using MongoDB with Spring .
It's the first time I'm using noSQL database and over all the experience is pretty good.

One of the reasons that required noSQL DB usage was the fact, that various entities can have unknown number of attributes. Furthermore that number can vary depending on the entity internal type.  

If I use an Endpoint entity as an example, it would look like this:

// BaseModel it's a parent class containing a single field
//  @Id
//  protected  String _id; 

@Document(collection = "endpoint")
public class Endpoint extends BaseModel {

    private String name;
    private String description;
    private String endpointType;
    private Collection attributes;

// getters and setters
}

The Attribute class looks like this:
public class Attribute extends BaseModel {
 
    private String parentObjectName;
    private AttributeType attributeType;
    private String name;
    private String displayName;
    private String fullName;
    private T value;
    private T defaultValue;
    // add getters and setters 
  }

and AttributeType is a simple enum:
public enum AttributeType {
    STRING,LONG,INTEGER,DATE,DATE_TIME,ENUM,PASSWORD,BOOLEAN,TEXT_AREA;
}

So everything is fine as long we don't have any security concerns. But an Attribute may contain a password information, in that case we would like to use some kind of bi-directional encryption (AES for instance) to encrypt the attribute value before it's being written to the DB and decrypt it right after it's read from the DB.
Since such attributes collections can be member of more than a single class, we need an infrastructural solution.

If we extend AbstractMongoEventListener class we'll achieve a listener that will be called on each one of the following occasions:

  • onBeforeConvert
  • onBeforeSave
  • onAfterSave
  • onAfterConvert  

for each entity that being saved or retrieved from the DB.

In our case we need to override 2 methods:

    @Override
    public void onBeforeConvert(Object source) {
        super.onBeforeConvert(source);
        passwordsPersistenceCare(source,true);
    }

//........
   @Override
    public void onAfterConvert(DBObject dbo, Object source) {
        super.onAfterConvert(dbo, source);
        passwordsPersistenceCare(source,false);
    }


To summarize:
Having some kind of general operation on certain  entity type, before it's written to MonogDb and\or after it's read from the DB, we can  extend AbstractMongoEventListener in order to gain a single location that will allow us to perform such an operation.
Another example that using the technique described above can be found here in Maciej Walkowiak blog

You can see the full code in the gist bellow: 
https://gist.github.com/IVedmak/7ec70d6744743a3c30eb

UPDATED:
See  gist with complete implementation of the listener that supports more complex data structures and UCs:
1)Attributes collection located in the objects that is deeper than the 1st level
2)The object with attributes collection is a part of the Map object
3)If any of the objects in memory instance used after the encryption and saving it, it's should be decrypted 1st
4)If the same object being referenced by more than one parent object it's should not be encrypted or decrypted twice 

Saturday, May 17, 2014

Linear gauge with gradient fill

In my searches for linear gauge control I didn't find any viable solution.
So I've created one based on D3 stacked bar graph.
See JSFiddle for implementation details

The final result will be something like this:


The Html will be pretty simple, only the container where we will put all the drawing

<div id="linearGaugeContainer"></div>

 I'm using SVG gradients definition in this sample

<!--define svg gradients to be used in java script. make sure the svg tag takes no room on your page=> width and height = 0px-->
<svg style="height: 0px; width: 0px;" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <lineargradient id="NORMAL_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0%" stop-color="#C1DC99" stop-opacity="1">
            <stop offset="100%" stop-color="#669900" stop-opacity="1">
        </stop></stop></lineargradient>
        <lineargradient id="WARNING_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0%" stop-color="#84C6F6" stop-opacity="1">
            <stop offset="100%" stop-color="#6FA7CF" stop-opacity="1">
        </stop></stop></lineargradient>
        <lineargradient id="MINOR_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0%" stop-color="#FFE537" stop-opacity="1">
            <stop offset="100%" stop-color="#F9C328" stop-opacity="1">
        </stop></stop></lineargradient>
        <lineargradient id="MAJOR_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0%" stop-color="#FF9900" stop-opacity="1">
            <stop offset="100%" stop-color="#FF6700" stop-opacity="1">
        </stop></stop></lineargradient>
        <lineargradient id="CRITICAL_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0%" stop-color="#E70030" stop-opacity="1">
            <stop offset="100%" stop-color="#B30020" stop-opacity="1">
        </stop></stop></lineargradient>
    </defs>
</svg>

The javascript code is a bit long, just follow the comments within the code:

//Linear gauge
//The way to implement it would be: 
// - To take a stacked bar graph as a basis
// - Ignore all the graph related attributes 
//   (like: axis, ticks and so on)
// - Define a single set of data 
// - Swap the x and y axis values
var margins = {
    top: 12,
    left: 48,
    right: 24,
    bottom: 24
},
width = 700 - margins.left - margins.right
    height = 15,
    dataset = [{
        data: [{
            barId: '1', // we assign some random value, the most important to keep it same for all the entries 
            percent: 0.1, // percentage that we want a specific value to occupy as a part of the gauge: values betwee 0-1
            severity: 'NORMAL_COLOR'// color id that we'll used to reference gradient value
        }]
    }, {
        data: [{
            barId: '1',
            percent: 0.4,
            severity: 'WARNING_COLOR'
        }]
    }, {
        data: [{
            barId: '1',
            percent: 0.22,
            severity: 'MINOR_COLOR'
        }]
    }, {
        data: [{
            barId: '1',
            percent: 0.2,
            severity: 'MAJOR_COLOR'
        }]
    }, {
        data: [{
            barId: '1',
            percent: 0.08,
            severity: 'CRITICAL_COLOR'
        }]
    }],
    dataset = dataset.map(function (d) {
        return d.data.map(function (o, i) {
            // Structure it so that your numeric
            // axis (the stacked amount) is y
            return {
                y: o.percent,
                x: o.barId,
                severity:o.severity
            };
        });
    }),
    stack = d3.layout.stack();

stack(dataset);


var dataset = dataset.map(function (group) {
    return group.map(function (d) {
        // Invert the x and y values, and y0 becomes x0
        return {
            x: d.y,
            y: d.x,
            x0: d.y0,
            severity:d.severity
            
        };
    });
}),
    svg = d3.select('#linearGaugeContainer')
        .append('svg')
        .attr('width', width + margins.left + margins.right)
        .attr('height', height + margins.top + margins.bottom)
        .append('g')
        .attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
    xMax = d3.max(dataset, function (group) {
        return d3.max(group, function (d) {
            return d.x + d.x0;
        });
    }),
    xScale = d3.scale.linear()
        .domain([0, xMax])
        .range([0, width]),
    yValue = dataset[0].map(function (d) {
        return d.y;
    }),
    yScale = d3.scale.ordinal()
        .domain(yValue)
        .rangeRoundBands([0, height], .1),
    // this color funciton referencing the linearGradient defind in the HTML part by id 
    color = function (index) {
        console.log(dataset[index][0])
        return "url(#" + dataset[index][0].severity + ")";
    },
    groups = svg.selectAll('g')
        .data(dataset)
        .enter()
        .append('g')
        .style('fill', function (d, i) {
        return color(i);
    });
    var rects = groups.selectAll('rect')
        .data(function (d) {
        return d;
    }).enter();
    rects.append('rect')
        .attr('x', function (d) {
        return xScale(d.x0);
    })
        .attr('y', function (d, i) {
        return yScale(d.y);
    })
        .attr('height', function (d) {
        return yScale.rangeBand();
    })
        .attr('width', function (d) {
        return xScale(d.x);
    });
// locate a label with percentage above each section of the gauge    
rects.append("text")
      .text(function(d,i) { return (d.x * 100) + '%' })
      .attr("x", function(d) { return xScale(d.x0); })
      .style("stroke", '#000000')