1 /*
  2  * Copyright © [2008-2009] Novell, Inc.  All Rights Reserved.
  3  * 
  4  * USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE DEVELOPER LICENSE AGREEMENT
  5  * OR OTHER AGREEMENT THROUGH WHICH NOVELL, INC. MAKES THE WORK AVAILABLE.  THIS WORK 
  6  * MAY NOT BE ADAPTED WITHOUT NOVELL'S PRIOR WRITTEN CONSENT.
  7  * 
  8  * NOVELL PROVIDES THE WORK "AS IS," WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, 
  9  * INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR 
 10  * A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  NOVELL, THE AUTHORS OF THE WORK, AND THE 
 11  * OWNERS OF COPYRIGHT IN THE WORK ARE NOT LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER 
 12  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, 
 13  * OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS IN THE WORK.
 14  */
 15 
 16 /**
 17  * @fileoverview
 18  * This file defines the Asset class, which represents enterprise assets that might be referenced in events.
 19  * This asset information is stored in the Sentinel database and is attached to inbound
 20  * events as referential metadata which can be accessed by right-click menu functions.
 21  * @name Asset Class
 22  */
 23 
 24 /**
 25  * Constructs an instance of the Asset class which represents objects managed by Sentinel.
 26  * @example
 27  * var asset1 = new Asset();
 28  * asset.Description = "Main web server";
 29  * asset.IPv4 = "10.0.0.23";
 30  * var asset2 = new Asset({IPv4:"10.0.0.24",Vendor:"Novell"});
 31  * asset2.MAC = "0f:34:23:12:56:23";
 32  * asset.save();
 33  * asset2.save();
 34  * @class
 35  * The Asset class provides methods to store asset information representing enterprise
 36  * assets. This asset information is used to provide additional metadata to aid in analysis
 37  * of inbound events; the mapping service is used to "attach" asset information to these events.
 38  * The class accepts a pre-defined set of asset attributes:
 39  * <ul>
 40  * <li>GUID {GUID} : Unique identifier for this asset (assigned by Sentinel)
 41  * <li>IPv4* {String} : The IPv4 address of the asset, in dotted-quad notation; this is required
 42  * <li>IPv6 {String} : The IPv6 address of the asset (eight groups of four hex digits, colon-separated)
 43  * <li>Customer* {Customer} : The customer who owns this asset (defines a namespace)
 44  * <li>Hostname {String} : The hostname of the asset as provided by a name service (DNS, WINS)
 45  * <li>MAC {String} : The MAC address of the asset (hex pairs, colon separated)
 46  * <li>Category^ {String} : The class of asset being described (server|desktop|laptop|etc)
 47  * <li>Description {String} : A readable description of the asset
 48  * <li>Value {String} : The value of the asset, in terms of currency
 49  * <li>Criticality^ {String} : The criticality rating of the asset (low|med|high)
 50  * <li>Vendor {String} : The vendor which provides this asset
 51  * <li>Product {String} : The product name of this asset
 52  * <li>Version {String} : The product version of this asset
 53  * <li>Owner {Identity} : The owner of this asset
 54  * <li>Maintainer {Identity} : The maintainer of this asset
 55  * <li>BusinessUnit {String} : The business unit which holds this asset
 56  * <li>Department^ {String} : The department which holds this asset
 57  * <li>Location {String} : The location at which this asset is located; use internal codes or full address
 58  * <li>Coordinates {Coordinates} : The latitude/longitude coordinates of the asset (not yet implemented)
 59  * </ul>
 60  * * : This field is used as a key field for mapping metadata into the event
 61  * ^ : This field is copied into the raw event structure for use in correlation. Other fields are
 62  * available via lookup for reporting.
 63  * 
 64  * @author   Novell Engineering
 65  * @version  6.1
 66  * @param {Object} properties  Set of pre-defined properties used to initialize this object
 67  * @constructor
 68  */
 69 function Asset(properties) {
 70 	if( typeof properties != "undefined") {
 71 		// Poor man's Impl
 72 		for (var field in properties) {
 73 			if (typeof AssetImpl[field] != "undefined") {
 74 				this[field] = properties[field];
 75 			}
 76 		}
 77 	}
 78 	return true;
 79 	
 80 	// Never accessed, but defined here for documentation
 81 	
 82 	/**
 83 	 * Unique identifier for this asset (assigned by Sentinel).
 84 	 * @type UUID
 85 	 */
 86 	this.GUID;
 87 	
 88 	/**
 89 	 * The IPv4 address of the asset, in dotted-quad notation (leave blank for dynamic address allocation).
 90 	 * Used as a key field when matching against event data. One of Hostname or IPv4 are required.
 91 	 * @type String
 92 	 */
 93 	this.IPv4; 
 94 	
 95 	/**
 96 	 * The IPv6 address of the asset (eight groups of four hex digits, colon-separated).
 97 	 * @type String
 98 	 */
 99 	this.IPv6;
100 	
101 	/**
102 	 * The customer who owns this asset (defines a namespace).
103 	 * This field will typically be set based on the MSSP Customer Name parameter for the Collector,
104 	 * unless the Collector processes data from multiple customers. It should match the Customer 
105 	 * injected into event data based on event Collectors' MSSP Customer Name parameter.
106 	 * Used as a key field when matching against event data.
107 	 * @example
108 	 * var asset = new Asset(); 
109 	 * var id = Customer.getId(custname);
110 	 * asset.CustomerID = id;
111 	 * @type String
112 	 */
113 	this.Customer;
114 	
115 	/**
116 	 * The hostname of the asset as provided by a name service (DNS, WINS). One of Hostname or IPv4 are required.
117 	 * @type String
118 	 */
119 	this.Hostname;
120 	
121 	/**
122 	 * The MAC address of the asset (hex pairs, colon separated)
123 	 * @type String
124 	 */
125 	this.MAC;
126 	
127 	/**
128 	 * The class of asset being described. Novell recommends developing an enumerated list of asset
129 	 * categories (such as server|desktop|laptop|etc) and restricting this field to those possibilities.
130 	 * This will allow for easier correlation based on the asset category.
131 	 * This field is injected into events if the assets referenced in the event matches.
132 	 * @type String
133 	 */
134 	this.Category;
135 	
136 	/**
137 	 * A readable description of the asset.
138 	 * @type String
139 	 */
140 	this.Description;
141 	
142 	/**
143 	 * The value of the asset, in terms of currency. Novell recommends normalizing to a specific
144 	 * currency so that numeric tests can be applied in correlation.
145 	 * @type String
146 	 */
147 	this.Value;
148 	
149 	/**
150 	 * The criticality rating of the asset (low|med|high). Novell recommends developing an enumerated list of asset
151 	 * criticalities (such as low|med|high) and restricting this field to those possibilities.
152 	 * This will allow for easier correlation based on the asset criticality.
153 	 * This field is injected into events if the assets referenced in the event matches.
154 	 * @type String
155 	 */
156 	this.Criticality;
157 	
158 	/**
159 	 * The vendor which provides this asset.
160 	 * @type String
161 	 */
162 	this.Vendor;
163 	
164 	/**
165 	 * The product name of this asset.
166 	 * @type String
167 	 */
168 	this.Product;
169 	
170 	/**
171 	 * The product version of this asset.
172 	 * @type String
173 	 */
174 	this.Version;
175 	
176 	/**
177 	 * The owner of this asset. Note that this is an Identity, so you must find the Identity before
178 	 * you can set this field.
179 	 * @example
180 	 * var asset = new Asset();
181 	 * var myIdens = Identity.find({PrimaryEmail : "user1@novell.com"});
182 	 * if (myIdens.length() == 1) { 
183 	 * 	asset.Owner = myIdens[0];
184 	 * }
185 	 * @type Identity
186 	 */
187 	this.Owner;
188 
189 	/**
190 	 * The maintainer of this asset. Note that this is an Identity, so you must find the Identity before
191 	 * you can set this field.
192 	 * @example
193 	 * var asset = new Asset();
194 	 * var myIdens = Identity.find({PrimaryEmail : "user2@novell.com"});
195 	 * if (myIdens.length() == 1) { 
196 	 * 	asset.Maintainer = myIdens[0];
197 	 * }
198 	 * @type Identity
199 	 */
200 	this.Maintainer;
201  
202 	/**
203 	 * The business unit which holds this asset.
204 	 * @type String
205 	 */
206 	this.BusinessUnit;
207 	
208 	/**
209 	 * The department which holds this asset.
210 	 * This field is injected into events if the assets referenced in the event matches.
211 	 * @type String
212 	 */
213 	this.Department;
214 	
215 	/**
216 	 * The location at which this asset is located; use internal codes or full address.
217 	 * @type String
218 	 */
219 	this.Location;
220 	
221 	/**
222 	 * The latitude/longitude coordinates of the asset (not yet implemented).
223 	 * @type Coordinates
224 	 */
225 	this.Coordinates;
226 };
227 
228 // Used as a reference for what attributes are allowed
229 AssetImpl = {"IPv4":null,"IPv6":null,"Customer":null,"Hostname":null,"MAC":null,
230 	"Category":null,"Description":null,"Value":null,"Criticality":null,"Vendor":null,
231 	"Product":null,"Version":null,"BusinessUnit":null,"Department":null,"Location":null,
232 	"Coordinates":null};
233 
234 
235 /**
236 * This method saves the Asset object in the Sentinel database.
237 * <p>Example:
238 * <pre>
239 * this.testasset = new Asset({"Hostname":"testname","IPv4":"10.0.0.12"});
240 * this.testasset.save();
241 * </pre> 
242 * @return {Boolean} Result  Result of the attempted save.
243 */
244 Asset.prototype.save = function() {
245 	
246 	/*
247 	 * This method will use the following translation between the JS Asset object and the Sentinel "infoblock" fields:
248 	 * [JS Asset attribute] -> [Infoblock tag]
249 	 * GUID -> EnvironmentIdentity
250 	 * IPv4 -> IpAddress
251 	 * IPv6 -> NetworkIdentity
252 	 * Customer -> CustomerName 
253 	 * Hostname -> HostName
254 	 * MAC -> MacAddress
255 	 * Category -> AssetCategory
256 	 * Description -> AssetName
257 	 * Value -> AssetValue
258 	 * Criticality -> Criticality
259 	 * Vendor -> Vendor
260 	 * Product -> ProductName
261 	 * Version -> ProductVersion
262 	 * Owner.PrimaryEmail -> OwnerEmail
263 	 * Owner.FirstName -> OwnerFirstName
264 	 * Owner.LastName -> OwnerLastName
265 	 * Owner.PrimaryPhone -> OwnerPhoneNumber
266 	 * Owner.IdentityGuid -> Room  (We are "faking" an FK over to Identity)
267 	 * Maintainer.PrimaryEmail -> MaintainerEmail
268 	 * Maintainer.FirstName -> MaintainerFirstName
269 	 * Maintainer.LastName -> MaintainerLastName
270 	 * Maintainer.PrimaryPhone -> MaintainerPhoneNumber
271 	 * Maintainer.IdentityGuid -> RackNumber (We are "faking" an FK over to Identity)
272 	 * BusinessUnit -> BusinessUnit
273 	 * Department -> Department
274 	 * Location -> AddressLine1
275 	 * Coordinates -> AddressLine2
276 	 * AssetEntryType will be hardcoded to "physical"
277 	 */
278 	
279 	// Must have one of these set
280 	if (!this.IPv4 || !(/^\d+\.\d+\.\d+\.\d+$/.test(this.IPv4) )) {
281 		log("Attempt to save an asset without a valid IP address");
282 		return false;
283 	}
284 	
285 	var owneremail,ownerfirst,ownerlast,ownerphone,ownerguid;
286 	var maintaineremail,maintainerfirst,maintainerlast,maintainerphone,maintainerguid;
287 	
288 	// For some strange reason, First/Last must be unique or later records will overwrite this one
289 	if (this.Owner instanceof IdentityImpl && this.Owner.PrimaryEmail && this.Owner.PrimaryEmail != "") {
290 		owneremail = this.Owner.PrimaryEmail;
291 		ownerfirst = (!this.Owner.FirstName || this.Owner.FirstName == "null") ? this.Owner.PrimaryEmail.split("@")[0] : this.Owner.FirstName;
292 		ownerlast = (!this.Owner.LastName || this.Owner.LastName == "null") ? this.Owner.PrimaryEmail.split("@")[1] : this.Owner.LastName;
293 		ownerphone = this.Owner.PrimaryPhone == "null" ? "" : this.Owner.PrimaryPhone;
294 		ownerguid = this.Owner.IdentityGuid;
295 	}
296 	
297 	if (this.Maintainer instanceof IdentityImpl && this.Maintainer.PrimaryEmail && this.Maintainer.PrimaryEmail != "") {
298 		maintaineremail = this.Maintainer.PrimaryEmail;
299 		maintainerfirst = (!this.Maintainer.FirstName || this.Maintainer.FirstName == "null") ? this.Maintainer.PrimaryEmail.split("@")[0] : this.Maintainer.FirstName;
300 		maintainerlast = (!this.Maintainer.LastName || this.Maintainer.LastName == "null") ? this.Maintainer.PrimaryEmail.split("@")[1] : this.Maintainer.LastName;
301 		maintainerphone = this.Maintainer.PrimaryPhone == "null" ? "" : this.Maintainer.PrimaryPhone;
302 		maintainerguid = this.Maintainer.IdentityGuid;
303 	}
304 	
305 	var infoSession = new InfoBlockSession("asset", new ContextInfoSender(instance.CONFIG.scriptContext));
306 	
307 	if (typeof this.GUID == "undefined") {
308 		//this.GUID = new Date.UTC();
309 	}
310 	
311 	var fields = new Array("AssetEntryType","EnvironmentIdentity","IpAddress","NetworkIdentity","CustomerName",
312 			"HostName","MacAddress","AssetCategory","AssetName","AssetValue","Criticality",
313 			"Vendor","ProductName","ProductVersion",
314 			"OwnerEmail","OwnerFirstName","OwnerLastName","OwnerPhoneNumber","Room",
315 			"MaintainerEmail","MaintainerFirstName","MaintainerLastName","MaintainerPhoneNumber","RackNumber",
316 			"BusinessUnit","Department","AddressLine1","AddressLine2");
317 	var values = new Array("physical",this.GUID,this.IPv4,this.IPv6,this.Customer ? this.Customer.Name : "unknown",
318 			this.Hostname,this.MAC,this.Category,this.Description,this.Value,this.Criticality,
319 			this.Vendor,this.Product,this.Version,
320 			owneremail,ownerfirst,ownerlast,ownerphone,ownerguid,
321 			maintaineremail,maintainerfirst,maintainerlast,maintainerphone,maintainerguid,
322 			this.BusinessUnit,this.Department,this.Location,this.Coordinates);
323 	
324 	var Jfields = fields.toJava(java.lang.String);
325 	var Jvalues = values.toJava(java.lang.String);
326 	
327 	infoSession.setTag(Jfields, Jvalues );
328 	
329 	infoSession.push();
330 	infoSession.send();
331 	infoSession.close();
332 };
333 
334 /**
335  * Finds the asset(s) in the Sentinel database.
336  * NOT YET IMPLEMENTED.
337  * @return {Asset[]}  Matching assets.
338  */
339 Asset.prototype.find = function() {
340 	return null;
341 };