How To: December, 11th 2009
How To: December, 11th 2009
HOW TO
[Link]
Copyright 2006-2009 France Telecom License information: [Link]
Table of contents
[Link]......................................................................................................3 [Link].........................................................................................................3 [Link]...........................................................................................................3 [Link]..............................................................................................................4 [Link].......................................................................................................4 [Link]...........................................................................................................................4 [Link].......................................................................................................................4 [Link].............................................................................6 [Link]......................................................................................6 [Link]...................................................................................................11 [Link]................................................................................................11 [Link].................................................................................13 [Link]................................................................................................14 [Link]..................................................................................................................16 [Link]..............................................................................................................19 [Link]...............................................................24
December,11th2009
performing actions (i.e. generating requests) on the SUT, using and managing specific protocols whose response times will be measured (e.g. HTTP, DNS, JDBC, TCP/IP, DHCP, SIP, LDAP); providing conditions used by the behaviors' conditional statements (if-then-else, while, preemptive); providing timers to implement delays (think time), for example with specific random distributions or computed in some arbitrary way; providing ad hoc controls for the plug-in itself (e.g. to change some settings); providing support for external data provisioning (e.g. a database of product references or a file containing identifier-password pairs for some user accounts), used as parameters by the behaviors.
2.1.2. Attributes
Each attribute has a name and normally contains data. Attributes are always associated with (are members of) one or more ObjectClasses. Attributes have a number of interesting characteristics: 1. All attributes are members of one or more objectclass(es) 2. Each attribute defines the data type that it may contain. 3. Attributes can be optional or mandatory, 4. Attributes can have single or multi values, 5. Attributes have names and sometimes aliases or abbreviations, 6. At each level in the hierarchy the data contained in one attribute should uniquely identify the entry. It can be any attribute in the entry. It can even be a combination of two or more attributes.
2.1.3. ObjectClass
ObjectClasses are essentially packages of attributes. There are a confusing number of predefined objectClasses, each of which contains bucket-loads of attributes for almost all common or garden applications. But of course the one you NEED is never defined! objectclasses have two more characteristics: 1. The objectclass defines whether an attribute member MUST (mandatory) be present or MAY (optional) be present.
December,11th2009
2. The objectclass may be part of a hierarchy in which case it inherits all the characteristics of its parent objectclasses.
instantiating new session objects for new behavior instances; implementing load injection primitives; implementing timer primitives (e.g. to implement think times); implementing external data provisioning; implementing condition primitives; session object control primitives.
The primitives offered by an ISAC plug-in, as well as a GUI-oriented description for its parameters, are declared through 3 descriptor files: [Link] specifies Java properties [Link], [Link] and [Link] to respectively set the ISAC plug-in name, the name of the XML file describing the list of primitives and parameters, and the name of the XML file describing the GUI concerns. Usual values for these file names respectively are [Link] and [Link]. [Link] (or any other name as specified in [Link] file) [Link] (or any other name as specified in [Link] file)
December,11th2009
To be able to act on an LDAP directory we need some specific libraries. You have to get [Link] and [Link]. You can get these librairies into the LdapInjector/lib directory, Once you have them, create repertory lib in MyLdapInjector and paste them into it.
From the Eclipse-RCP standalone console you can use the ISAC plug-in creation Wizard: Click on: File > New > ISAC Plug-in Project
Enter your project name: in our case MyLdapInjector Enter your project location (refer to the repertory that you created before). In our case the location is: /path/to/the/eclipseStandAloneConsole/clif-<versions>eclipseconsole/plugins/[Link].plugin_2.0.0/isac/plugins/MyLdapInjector
December,11th2009
In the Java settings, you have to add LDAP libraries ([Link] and [Link]) to your classpath.
How To develop ISAC plug-ins for CLIF v2 Click on the Next button. Set the plug-in properties. Most of them have default values.
You will need to tick the Implements DataProvider interface box if your plug-in have to provide data. You can now click on the Finish button. The Eclipse Isac perspective will be loaded. It is recommended to click on Finish now to be sure that all settings will be saved in case of an Eclipse crash.
10
December,11th2009
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plugin PUBLIC "-//[Link]//DTD CLIF Isac 1.0//EN" "classpath:org/objectweb/clif/scenario/isac/dtd/[Link]"> <plugin name="MyLdapInjector"> <object class="[Link]"> <params></params> <help>Give object help.</help> </object> </plugin>
The user interface descriptor file ([Link] by default) adds explicit labels to primitives and parameters, and associates each parameter to GUI-related information. Possible graphical
11
How To develop ISAC plug-ins for CLIF v2 widgets are available through the following tags : radiobutton, field, checkbox, nfield (variable number of fields), combo. Parameters may also be visually grouped together with the group tag. The parameter value resulting from a nfield widget is the concatenation of the variable number of fields separated by one ';' character.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE gui PUBLIC "-//[Link]//DTD CLIF IsacGUI 1.0//EN" "classpath:org/objectweb/clif/scenario/isac/dtd/[Link]"> <gui> <object name="SessionObject"> <params></params> </object> </gui>
The Eclipse wizard also creates a [Link] file which will be used when you will use the ant isacclean and ant isac-plugins tasks of the [Link] file present in the following directory: clif-<version>-consoleplugins\[Link].plugin_<plugin_version> This XML file contains several ant tasks:
<?xml version="1.0" encoding="UTF-8"?> <project name="ISAC-plugin_MyLdapInjector" default="compile"> <!-- This [Link] file must be called from CLIF main [Link] file. 4 properties are provided by CLIF main [Link] file: - [Link], all Jars used by the plugin must be copied to this directory - [Link], classpath for full CLIF runtime library - [Link], build directory (where classes must be generated and necessary resource files, if any, must be copied) [Link], ISAC root directory -->
<!-- General Configuration --> <property name="[Link]" value="${[Link]}/plugins/MyLdapInjector"> </property> <!-- classpath definition --> <path id="[Link]"> <pathelement path="${[Link]}"></pathelement> <pathelement path="${[Link]}"></pathelement> </path> <target name="compile"> <javac srcdir="${[Link]}/src" destdir="${[Link]}" classpathref="[Link]"> </javac> <copy todir="${[Link]}/MyLdapInjector"> <fileset dir="${[Link]}" includes="[Link],[Link],[Link]"> </fileset> </copy> </target> <target name="clean"></target> </project>
12
/** * Implementation of a session object for plugin ~MyLdapInjector~ */ public class SessionObject implements SessionObjectAction, DataProvider { /** * Constructor for specimen object. * * @param params key-value pairs for plugin parameters */ public SessionObject(Hashtable params) {} /** * Copy constructor (clone specimen object to get session object). * * @param so specimen object to clone */ private SessionObject(SessionObject so) {} //////////////////////////////////////// // SessionObjectAction implementation // //////////////////////////////////////// /** * @see [Link]#createNewSessionObj ect() */ public Object createNewSessionObject() { return new SessionObject(this); } /** * @see [Link]#close() */ public void close() {} /** * @see [Link]#reset() */ public void reset() {}
13
To define these primitives we will use the Eclipse wizard. Right click on the MyLdapInjector project, then click on properties:
14
December,11th2009
15
How To develop ISAC plug-ins for CLIF v2 Now with the ISAC Plugin menu you will be able to define:
After adding contextual help you can define groups of global parameters. For example, you can define a group that contain severals parameters. Click on to add a group in the session object.
16
December,11th2009
Then you can add several parameters into the group that you have created. First of all, select it, and then click on
Do it with all your parameters. If you want to add parameters which are not connection parameters you have to click first on root and then on Finally you will have something like that: Now you have to give each parameter a name, a type, a default text value if necessary, a list of values, depending of the parameters you are defining.
17
field
18
December,11th2009
nfield table radio button checkbox combo In your case (LDAP injector) you will choose field type for all parameters.
So you just have to define a Label (this will be the label displayed when you will write your ISAC scenario), the type, a text if our parameter has a default value and a length (this length represents the size of the input text field of the Isac scenario wizard). These actions with the wizard modify:
[Link] file adding parameters: <params> <param name="hostname" type="String"></param> <param name="version" type="String"></param> </params> [Link] files adding parameters:
<params> <group name="Ldap connection parameters"> <param label="Host name" name="hostname"> <field text="" size="8"></field> </param> </group> <param label="LDAP version" name="version"> <field text="" size="8"></field> </param> </params>
connection SSL connection closeConnection search add entry delete entry add attribute delete attributes
19
Click on the button and add all the primitives you want to define giving them a name and don't forget to write a description of all of them.
After adding the primitive's name and description you will have to add their specific attributes. Each primitive has specific attributes:
connection login: the login DN to connect to the LDAP directory password: the password to connect to the LDAP directory port: the port to connect using non-secure connection.
sslConnection
20
December,11th2009
login: the login DN to connect to the LDAP directory password: the password to connect to the LDAP directory port: The port to connect using secure connection. keystorePath: The path to access the keystore file.
closeConnection (no attributes) search searchBase: the place in the directory tree where to start to searching. (e.g. ou=people,dc=orange,dc=fr) searchFilter: the search filter (e.g. sn=fran*) searchScope: the search depth. (e.g. 2)
addEntry dn: the LDAP distinguished name entryNodeType: type of the node to insert (cn or sn or ou ou or uid) entryNodeName: name of the node to insert attributesList: node's list of attributes
deleteEntry dn: distinguished name representing the node to delete. addAttribute dn: distinguished name of the node where we want to add attributes attributesList: list of the couple attributes name / attributes values deleteAttribute dn: distinguished name of the node where we want to delete attributes attributestodelete: name of the attributes to delete.
Now we focus on the definition of the attributes of the addEntry primitive. To an add attribute just click on the add parameter button (notice that you can define group of attributes as with session object). The dn attribute has: label: Distinguished name type: field text: no default value length: 8
21
How To develop ISAC plug-ins for CLIF v2 The entryNodeType has: label: Insert node type type: combo
To add values to combobox click on and enter the different values with a default state (enabled or disabled).
The entryNodeName has: label: Insert node name type: field text: no default text length: 8
The attributesList has: label: List of attributes (scheme: name=value or name=value1,value2,value3) type: nfield
These actions with the wizard modify these files: [Link] class [Link] [Link]
This variable SAMPLE_ADDENTRY identifies the addEntry primitive in the LdapInjector plug-in. Each primitive has unique identifier.
static final int SAMPLE_ADDENTRY = 4;
The variables below are added when you define addEntry attributes. Each attributes of each primitive is identified with a variable which value is the variable name defined in the wizard.
static static static static final final final final String String String String SAMPLE_ADDENTRY_ATTRIBUTESLIST = "attributesList"; SAMPLE_ADDENTRY_ENTRYNODENAME = "entryNodeName"; SAMPLE_ADDENTRY_ENTRYNODETYPE = "entryNodeType"; SAMPLE_ADDENTRY_DN = "dn";
Adding samples with the wizard modify this Java class by adding a doSample() method which returns an ActionEvent object. This method has three parameters: The first argument gives the primitive identifier. The second parameter gives the list of parameter values indexed by their names, as set in the plug-in descriptor file using tag params;
22
December,11th2009
The third argument gives a report object whose fields will have to be filled before being returned.
Basically, the doSample() method is supposed to perform a load injection request, wait for some kind of response, state if this request is a success or a failure, measure its response time and return a sample report. Returning null is also possible, to make CLIF ignore this sample.
/**
@see [Link]#doSample()
*/ public ActionEvent doSample(int number, Map params, ActionEvent report) { switch (number) { case SAMPLE_DELETEATTRIBUTE: break; case SAMPLE_ADDATTRIBUTE: break; case SAMPLE_DELETEENTRY: break; case SAMPLE_ADDENTRY: break; case SAMPLE_SEARCH: break; case SAMPLE_SSLCONNECTION: break; case SAMPLE_CONNECTION: break; default: throw new Error("Unable to find this sample in ~LdapInjector~ ISAC plugin: " + number); } throw new IsacRuntimeException("No action defined for this sample in ~LdapInjector~ ISAC plugin: " + number); }
[Link]: In the [Link] file the addEntry sample is added with all its parameters and its help.
<sample name="addEntry" number="4"> <params> <param name="dn" type="String"></param> <param name="entryNodeType" type="String"></param> <param name="entryNodeName" type="String"></param> <param name="attributesList" type="String"></param> </params> <help>Add entry into an ldap directory.
 To be able to add an entry into ldap directory the following parameters are madatory:
 - Distinguished name
 - Node type (type of the node to insert) 
 - Node name (name of the node to insert)
 - List of the attributes: couple name=value(s) of the attributes which composed the node.</help> </sample>
[Link]:
23
The user interface descriptor file adds explicit labels to primitives and parameters, and associates each parameter to GUI related information. Graphical widgets appears here (combo, field, nfield).
<sample name="addEntry"> <params> <param label="Distinguished name" name="dn"> <field text="" size="8"></field> </param> <param label="Insert node type" name="entryNodeType"> <combo> <choice value="cn" default="false"></choice> <choice value="sn" default="false"></choice> <choice value="ou" default="false"></choice> <choice value="uid" default="false"></choice> </combo> </param> <param label="Insert node name" name="entryNodeName"> <field text="" size="8"></field> </param> <param label="List of attributes (sheme: name=value or name=value1,value2,value3)" name="attributesList"> <nfield></nfield> </param> </params> </sample>
In the SessionObject constructor we checked the value of the parameters. These must not be null or empty, they must be set.
/** * Constructor for specimen object. * * @param params key-value pairs for plugin parameters * @throws ClifException */ public SessionObject(Hashtable params) throws ClifException { // local address setting String value = (String)[Link](PLUGIN_HOSTNAME); if (value != null && [Link]() > 0) {
24
December,11th2009
try { hostname = value; } catch (Exception ex) { throw new ClifException("ISAC can't get hostname because the specified hostname is not valid: " + value, ex); } } else { throw new ClifException("ISAC can't get hostname because the specified hostname is not valid: " + value); } // ldap version setting value = (String)[Link](PLUGIN_VERSION); if (value != null && [Link]() > 0) { try { ldapVersion = [Link](value); } catch (Exception ex) { throw new ClifException("ISAC can't get LDAP version because the specified LDAP version is not valid: " + value, ex); } } else { throw new ClifException("ISAC can't get LDAP version because the specified LDAP version is not valid: " + value); } } /** * Copy constructor (clone specimen object to get session object). * * @param so specimen object to clone */ private SessionObject(SessionObject so) { [Link] = [Link]; [Link] = [Link]; }
Declare your LDAPConnection object to be able to access it from every implemented method which will manipulate your LDAP directory. This object will be instantiated in the doConnection() method.
private LDAPConnection ldapConnection;
All the methods implement for this LDAP injector have three parameters, like the doSample() method: The first argument gives the primitive identifier; The second parameter gives the list of parameter values indexed by their names, as set in the plug-in descriptor file using tag params; The third argument gives a report object whose fields will have to be filled before being returned. And return an ActionEvent.
These following methods are called by the doSample() method depending of the primitive identifier and need to be implemented: doConnection(int number, Map params, ActionEvent report); doSslConnection(int number, Map params, ActionEvent report); doAddEntry(int number, Map params, ActionEvent report);
25
doDeleteEntry(int number, Map params, ActionEvent report); doAddAttribute(int number, Map params, ActionEvent report); doDeleteAttribute(int number, Map params, ActionEvent report); doSearch(int number, Map params, ActionEvent report); doCloseConnection(int number, Map params, ActionEvent report);
/** * @see [Link]#doSample() */ public ActionEvent doSample(int number, Map params, ActionEvent report) { switch (number) { case SAMPLE_DELETEATTRIBUTE: return doDeleteAttribute(number, params, report); case SAMPLE_ADDATTRIBUTE: return doAddAttribute(number, params, report); case SAMPLE_DELETEENTRY: return doDeleteEntry(number, params, report); case SAMPLE_ADDENTRY: return doAddEntry(number, params, report); case SAMPLE_CLOSECONNECTION: return doCloseConnection(number, params, report); case SAMPLE_SEARCH: return doSearch(number, params, report); case SAMPLE_SSLCONNECTION: return doSslConnection(number, params, report); case SAMPLE_CONNECTION: return doConnection(number, params, report); default: throw new Error("Unable to find this sample in ~LdapInjector~ ISAC plugin: " + number); } }
First of all we have to declare and set attributes of the addEntry primitive. This parameters are in the params Map passed in parameter of the doAddEntry method. The get method applied on a Map returns an Object so we have to cast it into String to be able to use it.
String String String String dn = (String) [Link](SAMPLE_ADDENTRY_DN); insertNodeName = (String) [Link](SAMPLE_ADDENTRY_ENTRYNODETYPE); insertNodeValue = (String) [Link](SAMPLE_ADDENTRY_ENTRYNODENAME); attributesList = (String) [Link](SAMPLE_ADDENTRY_ATTRIBUTESLIST);
26
December,11th2009
Then we create a LDAPAttributeSet which is a collection of LDAPAttribute objects. LDAPAttributeSet may be used to build an entry to be added to a directory.
LDAPAttributeSet attributeSet = new LDAPAttributeSet();
The attributesList is a string represented by a sequence of couple name=value or name=value1,value2,value3... Each couple is separated by ;. We check if the entry node belongs to the attributesList. If it doesn't, we add it, at the end of the attributesList string:
if ([Link](insertNodeName) == -1) { attributesList = attributesList+insertNodeName+"="+insertNodeValue+";"; }
We check if the entry node belongs to the dn. If it doesn't, we add it, at the beginning of the dn string;
if ([Link](insertNodeName) == -1) { dn = insertNodeName+"="+insertNodeValue+","+dn; }
Then we have to transform the String attributesList into a String[] using the split method.
String[] tabParam_NameValue = [Link](";");
Now we can go into the String[] tabParam_NameValue and add LDAPAttribute to the LDAPAttributeSet:
String name = null; String[] values = null; for (int i = 0; i<tabParam_NameValue.length; i++) { name=tabParam_NameValue[i].substring(0, tabParam_NameValue[i].indexOf("=")); values=(tabParam_NameValue[i].substring(tabParam_NameValue[i].indexOf("=")+1, tabParam_NameValue[i].length())).split(","); [Link]( new LDAPAttribute( name, values )); }
Then we can create an LDAPEntry object with the dn and attributeSet as parameters.
LDAPEntry newEntry = new LDAPEntry( dn, attributeSet );
To be able to identify the add entry lines in the report file you can set the type parameter in the report object:
[Link] = "ADDENTRY_TYPE";
And you also need to set the Date parameter of the report object to be able to set the add entry duration.
[Link]([Link]());
27
Now you just have to add the entry in your LDAP directory. To do it, you have to apply the add method to the ldapConnection object which is a global attribute of the SessionObject class and which is initialized in the connection() method. Wee also have to catch exceptions and to set the result of the add, a comment, state of the add method (successful or not):
try { [Link]( newEntry ); [Link] = (int) ([Link]()); [Link] = true; [Link] = "Added object: " + dn + " successfully."; } catch (LDAPException ex) { [Link] = false; if ([Link]() == LDAPException.ATTRIBUTE_OR_VALUE_EXISTS) { [Link] = [Link](); [Link] = "Failed to add existing attribute."; } else { [Link] = [Link](); [Link] = "Failed to add attribute."; } } catch (Exception e) { [Link] = [Link](); [Link] = "Failed to add existing attribute."; }
To be able to test make a search in an LDAP directory you will need to implement doConnection(), doCloseConnection and search() methods. Here is the Java code of these methods:
/** * Does a connection to a LDAP directory (bind). * * @param number: The number which handles the connection to the ldap directory. * @param report: The ActionReport to update. * @param params: A Map containing all the useful variable. * @return the report. */ public ActionEvent doConnection(int number, Map params, ActionEvent report) { ldapConnection = new LDAPConnection(); String login = (String) [Link](SAMPLE_CONNECTION_LOGIN); String password = (String) [Link](SAMPLE_CONNECTION_PASSWORD); [Link] = "CONNECT_TYPE"; [Link]([Link]()); try { // connect to the server
28
December,11th2009
[Link]( hostname, [Link]((String) [Link](SAMPLE_CONNECTION_PORT))); // bind to the server [Link](ldapVersion, login, [Link]("UTF8")); [Link] = (int)([Link]() - [Link]()); [Link] = true; [Link] = "Successful bind with server."; } catch( LDAPException e ) { [Link] = false; [Link] = [Link](); [Link] = "ISAC LdapInjector error occured"; } catch( UnsupportedEncodingException e ) { [Link] = false; [Link] = [Link](); [Link] = "ISAC LdapInjector can't UTF8 encode password "+password; } return report; } /** * Close an opened connection to a LDAP directory (bind). * * @param number: The number which handles the connection to the ldap directory. * @param report: The ActionReport to update. * @param params: A Map containing all the useful variable. * @return the report. */ public ActionEvent doCloseConnection(int number, Map params, ActionEvent report) { if (ldapConnection != null) { [Link] = "DISCONNECT_TYPE"; [Link]([Link]()); try { // disconnect with the server [Link](); [Link] = (int)([Link]() [Link]()); ldapConnection = null; [Link] = true; [Link] = "ISAC LdapConnection disconnection Successful"; return report; } catch (LDAPException e) { [Link] = false; [Link] = "ISAC LdapInjector can't disconnect from " + hostname; [Link] = [Link](); return report; } } else { [Link] = false; [Link] = "ISAC LdapInjector can't disconnect unopen ldap connection";
29
/** * Does search into a LDAP directory. * * @param number: The number which handles the connection to the ldap directory. * @param report: The ActionReport to update. * @param params: A Map containing all the useful variable. * @return the report. */ public ActionEvent doSearch(int number, Map params, ActionEvent report) { try { [Link] = "SEARCH_TYPE"; [Link]([Link]()); LDAPSearchResults searchResults = [Link]((String) [Link](SAMPLE_SEARCH_SEARCHBASE),[Link]((String)[Link](SAMPLE _SEARCH_SEARCHSCOPE)),(String) [Link](SAMPLE_SEARCH_SEARCHFILTER),null,false); [Link]=(int)([Link]()-[Link]()); [Link] = true; [Link] = "LDAP Search succeded"; } catch( LDAPException e ) { [Link] = false; [Link] = [Link](); [Link] = "ISAC LdapInjector error occured"; } return report; }
[Link].
<?xml version="1.0" encoding="UTF-8"?> <project name="ISAC-plugin_MyLdapInjector" default="compile"> <!-- This [Link] file must be called from CLIF main [Link] file. 4 properties are provided by CLIF main [Link] file: - [Link], all Jars used by the plugin must be copied to this directory - [Link], classpath for full CLIF runtime library - [Link], build directory (where classes must be generated and necessary resource files, if any, must be copied) - [Link], ISAC root directory --> <!-- General Configuration --> <property name="[Link]" value="${[Link]}/plugins/MyLdapInjector"></property> <!-- classpath definition --> <path id="[Link]"> <pathelement path="${[Link]}"></pathelement> <pathelement path="${[Link]}"></pathelement> <fileset dir="${[Link]}/lib" includes="*.jar"></fileset> </path> <target name="compile">
30
December,11th2009
<javac srcdir="${[Link]}/src" destdir="${[Link]}" classpathref="[Link]"></ javac> <copy todir="${[Link]}" overwrite="yes" preservelastmodified="yes"> <fileset dir="${[Link]}/lib" includes="*.jar"></fileset> </copy> <copy todir="${[Link]}/MyLdapInjector"> <fileset dir="${[Link]}" includes="[Link],[Link],[Link]"></fileset> </copy> </target> <target name="clean"></target> </project> Now you just have to compile and make a jar file with all your ISAC plug-ins. Go to the following directory:
/path_to_your_clif_console/plugins/[Link].plugin_<version>
and launch the ant command: ant isac-plugins Once it is successful you can use your ISAC plug-in.
31