Using the LDAP Authentication Plugin for MediaWiki – The Basics (Part 2)

In part 1 of this series, I discussed basic password authentication for Active Directory (AD). In this article, I will discuss basic password authentication for LDAP domains with the posix schema.

For basic password authentication against an LDAP domain with the posix schema, you need to configure three or four things:

  1. Domain name
  2. Server names
  3. How to bind to the LDAP servers
  4. The proxy user used to find your user accounts (optional depending on your environment)

Prerequisites

Please see and complete the “Create a local sysop”, and “Enabling the plugin” sections of part 1 before proceeding.

Configuring the plugin

Setting the domain name

The domain name is used for all of the LDAP configuration settings, and is also the domain name visible to users when logging in. It is recommended to use the short name of your LDAP domain as the domain name. For example, if your LDAP domain is testposix.example.com, then you should use testposix as your domain name. We will use testposix for the examples in this post.

Place the following in LocalSettings.php file to set the domain name:

$wgLDAPDomainNames = array( "testposix" );

Setting the server names

The plugin needs to know the fully qualified domain name (FQDN) of each of your LDAP servers to contact. You may add multiple servers, delimited by spaces, for server failover.

Place the following in LocalSettings.php to set the server names:

$wgLDAPServerNames = array( "testposix" => "ldapserver1.testposix.example.com ldapserver2.testposix.example.com" );

Telling the plugin how to bind to the LDAP server

Binding to the LDAP server can be straightforward if your Directory Information Tree (DIT) is simple; by simple, I mean your users are in ou=people, and they all have the same naming attribute (such as uid). To bind to this type of DIT, you simply need a bind DN format, and a password. You can tell the plugin to create the bind dn by adding the following in LocalSettings.php:

$wgLDAPSearchStrings = array( "testposix" => "uid=USER-NAME,ou=people,dc=testposix,dc=example,dc=com";

Notice that USER-NAME is a special string, and should not be modified. When the user logs in, USER-NAME will be replaced with whatever username is used.

If your DIT is not flat, or your naming attributes aren’t the same for all users, you’ll need to configure the plugin to first find the user’s DN, then bind as that user. To do this, you’ll need a search attribute, a base DN, and optionally a proxy agent and proxy agent password.

Your search attribute must be an attribute that all users share, and should preferably be a unique attribute; we’ll use uid for this. Your base DN must be at a node in your tree that is a parent to all of your users; we’ll use dc=testposix,dc=example,dc=com for this (the root DN). If your directory server allows users to be searched anonymously (which is abnormal), you don’t need to specify and proxy agent or proxy agent password. If your directory server requires authenticated searches (normal), you can specify a proxy agent and proxy agent password; we’ll use cn=proxyagent,ou=profile,dc=testposix,dc=example,dc=com and “T3stP0$ixP@$$” for this. Notice that you should give the bare minimum privileges needed to the proxy agent!

You can set these options by placing the following into LocalSettings.php:

$wgLDAPSearchAttributes = array( "testposix" => "uid" );
$wgLDAPBaseDNs = array( "testposix" => "dc=testposix,dc=example,dc=com" );
$wgLDAPProxyAgent = array( "testposix" => "cn=proxyagent,ou=profile,dc=testposix,dc=example,dc=com" );
$wgLDAPProxyAgentPassword = array( "testposix" => "T3stP0$ixP@$$" );

By default the LDAP plugin is set to bind using encryption. Specifically, the plugin defaults to tls using LDAP (port 389). The supported encryption types are clear, tls, and ssl. Most posix LDAP servers support TLS and SSL. It is recommended to keep encryption enabled. If you need to switch encryption types, you can use the following option in LocalSettings.php:

$wgLDAPEncryptionType = array( "testposix" => "ssl" );

Configuring the server

Configuring the SSL trust

For ssl to work properly, it is important to ensure the LDAP client (the web server) trusts the root Certificate Authority (CA) of the LDAP server. If your organization is using a third party CA that is in most normal trust lists (like in IE or Firefox), this step can likely be skipped. If your LDAP servers are using self signed certificates or a local CA, this step is needed.

You can find out which CA issued the LDAP server’s certificate using openssl. Run the following command:

openssl s_client -connect ldapserver1.testposix.example.com:636 | egrep "subject|issuer"

If the subject and the issuer are the same, the certificate is self signed. If the subject and issuer are not the same, the certificate was signed by a CA. If the CA is local, ask someone in your organization for a copy of the CA certificate. If the certificate is self signed, you can get the certificate by running the previous command without the grep:

openssl s_client -connect ldapserver1.testposix.example.com:636

Copy everything in between, and including:

-----BEGIN CERTIFICATE-----

and:

-----END CERTIFICATE-----

Paste the text into a file, and place the file wherever your OS normally stores its CA certificates; Red Hat Enterprise Linux 5 and newer versions of Fedora place these in /etc/pki/tls/certs.

Now place the following into /etc/openldap/ldap.conf:

TLS_CACERT     <pathToCACert>
TLS_CACERTFILE <pathToCACert>

Restart your web server for this to take effect.

Test your configuration by logging in with an LDAP user

Everything should be working at this point. If you have any questions, you should post them on the discussion page for the plugin on mediawiki.org, or leave me a comment (the former is preferred).

28 Comments

  1. Hi, I have configured the wiki setup on Fedora core 11 , everithing is working fine and now I want to integare to LDAP [openLDAP]. I folloed the configuration given by you but is not working for me.

    I didnt find, any note on wher to copy or keep the plugin given here. I updated the ‘LocalSettings.php’ as described above. That is only I understood and updated. Is there any steps i need to follow? please help me to work this.

    Reply

    1. Did you get this working, or do you still need help? I haven’t been getting comment emails sent to me, so I’ve been kind of MIA.

      Reply

  2. hello,

    thanks for your page;it’s perfect !
    Do you try to restrict the access using groups ? I mean users authenticate and the system also verify if they belong to a particular group ?

    Thanks
    Bruno

    Reply

    1. Yes, you can do group restriction or group synchronization. See:

      http://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Configuration

      If you do group synch, you’ll also need to setup group rights to do any restrictions.

      Reply

  3. here is my configuration.

    require_once( “extensions/LDAP/LdapAuthentication.php” );
    $wgAuth = new LdapAuthenticationPlugin();
    $wgLDAPDomainNames = array( ‘adtest’);
    $wgLDAPServerNames = array( ‘adtest’ => ‘myldap-server’);
    $wgLDAPSearchStrings = array( ‘adtest’ => ‘uid=USER-NAME,ou=People,dc=[...]fr’);
    $wgLDAPSearchAttributes = array( “adtest” => “uid” );
    $wgLDAPBaseDNs = array( ‘adtest’ => ‘dc=[...]fr’);
    $wgLDAPEncryptionType = array( ‘adtest’ => ‘ssl’);

    If I stop here, it works, i.e. users can authenticate.

    But I want to enable group restriction, so I add :

    $wgLDAPGroupsUseMemberOf = array( “adtest” => “true”);
    $wgLDAPRequiredGroups = array( “adtest” => array(“cn=wikiusers,ou=group,ou=People,dc[...]fr”) );
    $wgLDAPGroupObjectclass = array(
    “adtest”=>”posixGroup” );
    $wgLDAPGroupAttribute = array( “adtest”=>”memberUid” );
    $wgLDAPGroupNameAttribute = array( “adtest”=>”cn” );

    $wgLDAPUseLocal = true;
    $wgMinimalPasswordLength = 1;

    Do you see what I missed ? I think the pb is in the wgLDAPGroupNameAttribute that I don’t understand…
    thanks a lot.
    Bruno

    Reply

    1. I reply to me :
      It works now :-))
      I added
      $wgLDAPDebug = 3;

      and saw that the current user didn’t have the right to get information about the ldap groups…

      Bruno

      Reply

  4. Hi,
    I am a novice in Linux and Wiki as well.
    I have managed to setup my openSuSe 11.1 an installed Mediawiki (a pure local machine).
    I would like to manage authentication through ldap. Therefore I have setup an ldap server which now runs and I am able to add and retrieve data from it.
    In addition I have setup an DNS. There I know the expression of a Domain.

    Question: Where to find the domain definition in my ldap, since nowhere during setup of the server a domain name has shown up.

    Regards
    Karl-Heinz

    Reply

    1. LDAP doesn’t have a domain per se. AD does because it uses Kerberos. If you use Kerberos with LDAP you specifically have a domain as well. However, many people use the term domain for LDAP as well. If I had “dc=example, dc=com” as my base dn, I could say it is the example domain, or the example.com domain.

      As far as the plugin is concerned, it doesn’t really matter what you call your domain. It is what users will see when they go to log in.

      Reply

  5. Hi,
    thanks – that helps.

    I have configured that way but the result is only “wrong password or password missing”

    require_once( “$IP/extensions/LdapAuthentication/LdapAuthentication.php” );
    $wgAuth = new LdapAuthenticationPlugin();
    $wgLDAPDomainNames = array( “averlon” );
    $wgLDAPRequiredGroups = array( “averlon”=>array(“cn=avwiki_users,ou=group,dc=averlon,dc=loc”) );
    $wgLDAPBaseDNs = array( “averlon”=>”dc=averlon,dc=loc” );
    $wgLDAPGroupUseFullDN = array( “averlon”=>false );
    $wgLDAPGroupObjectclass = array( “averlon”=>”posixgroup” );
    $wgLDAPGroupAttribute = array( “averlon”=>”memberuid” );
    $wgLDAPGroupSearchNestedGroups = array( “averlon”=>false );
    $wgLDAPGroupNameAttribute = array( “averlon”=>”cn” );

    Any idea why that password error shows up?
    Regards
    Karl-Heinz

    Reply

    1. Before you try to get group restrictions working, you should get regular authentication working. Also, you should turn on debugging, and look at the debug log. If you still need help, you should send me your debug log with sensitive stuff snipped out.

      Reply

  6. ok.
    next question is how to enable logging?

    $wgLDAPDebug = 3;
    $wgDebugLogFile = “/var/log/avwiki_log”;
    $wgDebugLogGroups["ldap"] = “/var/log/avwiki_ldap_log” ;
    $wgLogQueries = true;

    Thats what I have set. I would have expected to find a file at /var/log but there is none.

    Regards
    Karl-Heinz

    Reply

  7. my whole configuration now:

    require_once( “$IP/extensions/LdapAuthentication/LdapAuthentication.php” );
    $wgAuth = new LdapAuthenticationPlugin();
    $wgLDAPDebug = 3;
    $wgDebugLogFile = “/var/log/avwiki_log”;
    $wgDebugLogGroups["ldap"] = “/var/log/avwiki_ldap_log” ;
    $wgLogQueries = true;
    $wgLDAPDomainNames = array(
    “averlon”
    );
    $wgLDAPServerNames = array(
    “averlon” => “localhost”
    );
    $wgLDAPUseLocal = false;
    $wgLDAPEncryptionType = array(
    “averlon”=>”clear”
    );
    $wgLDAPBaseDNs = array(
    “averlon”=>”dc=averlon,dc=loc”
    );
    $wgLDAPUserBaseDNs = array(
    “averlon”=>”ou=people,dc=averlon,dc=loc”
    );
    $wgLDAPSearchStrings = array(
    “averlon” => “uid=USER-NAME,ou=people,dc=averlon,dc=loc”
    );
    $wgLDAPSearchAttributes = array(
    “averlon” => “uid”
    );
    $wgLDAPLowerCaseUsername = array(
    “averlon”=>true
    );
    $wgLDAPDisableAutoCreate = array(
    “averlon”=>true
    );

    I can see a trace on the top left corner of the wiki.

    If I use a name to login which existis in the ldap I get:

    Entering validDomain
    User is using a valid domain.
    Setting domain as: averlon
    Entering getCanonicalName
    Username isn’t empty.
    Munged username: Kalle
    Entering allowPasswordChange
    Entering modifyUITemplate

    If I use another name to login it works. But this name is also present in the local database of the wiki (since it is the admin). There I don’ t know whether authentication is realy done to the ldap or the local database.

    Reply

  8. Hi,
    it now works (without debugging).

    What I havn’ t found anywhere or havn’ t recognized is that all users have to be present in the local wiki database before they can login.
    If the user entry (name) is present, then the authentication (password check) will be done against ldap.

    I have other applications installed where this process runs different. They check whether the user is valid (uid and password against ldap) and if valid the check whether the user is present in the local db. If not, they automatically take over the user credentials to the local db.

    I would like to place this as a request to LDAPAuthentication Extension for Mediawiki.

    I now think to know why the user has to be present in the local db (as for the other application I am hosting as well), since the user preferences have to be handled locally.

    Thanks for your help and please check if the development request could be valid.

    Regards
    Karl-Heinz

    Reply

    1. The user doesn’t have to be present in the database before the user authenticates. The plugin will authenticate the user against LDAP, then if the user is not in the local database, MediaWiki creates the account in the local database. Notice that the user account does have to exist in the database after authentication because MediaWiki requires the user’s entry for a bunch of things.

      Reply

    2. Your specific problem is this line:

      $wgLDAPDisableAutoCreate = array(
      “averlon”=>true
      );

      Don’t set this. Someone requested this feature so that they can create accounts for people manually, and have the wiki send them a temporary password. I’m not an advocate of this set-up, and generally discourage its use unless you are letting the wiki manage the LDAP user accounts.

      When this is set, the wiki will authenticate the user against LDAP, but will not automatically create a local account. If a local account doesn’t exist, it essentially denies login. That is the reason you were seeing the behavior in question.

      Reply

  9. I’ve got a local test instance of Mediawiki installed locally on my MacBook, and I’m trying to get it to authenticate against our Snow Leopard Server OpenDirectory. Here’s the debug output when I try logging in:

    Entering validDomain
    User is using a valid domain.
    Setting domain as: sni
    Entering getCanonicalName
    Username isn’t empty.
    Munged username: Coleman
    Entering userExists
    Entering authenticate
    Entering Connect
    Using SSL
    Using servers: ldaps://server.company.net
    Connected successfully
    Entering getSearchString
    Doing a straight bind
    userdn is: uid=Coleman,ou=People,dc=company,dc=net
    Binding as the user
    Failed to bind as uid=Coleman,ou=People,dc=company,dc=net
    Entering allowPasswordChange
    Entering modifyUITemplate

    That’s the message, accompanied by an “incorrect password” message.

    Here’s my LocalSettings.php setup:

    require_once( “$IP/extensions/LdapAuthentication.php” );
    $wgAuth = new LdapAuthenticationPlugin();
    $wgLDAPDebug = 3;
    $wgDebugLogFile = “/Applications/XAMPP/xamppfiles/logs/wikildap_log”;
    $wgLDAPDomainNames = array(‘domain’);
    $wgLDAPServerNames = array(‘domain’ => ‘server.company.net’);
    $wgLDAPSearchStrings = array(‘sni’ => ‘uid=USER-NAME,ou=People,dc=company,dc=net’);
    $wgLDAPLowerCaseUsername = array(‘domain’ => true);
    $wgLDAPEncryptionType = array(‘domain’ => ‘ssl’ );
    $wgMinimalPasswordLength = 1;

    The SSL setup doesn’t seem to be causing any issues, I added the self-signed CA from the LDAP server on the Mediawiki side. It looks like it’s having trouble with the username for some reason, but I know I’m using the correct password. Does anything look off?

    Reply

  10. Hi,

    I’m trying to install this too. But i can’t log anything. i’ve put $wgLDAPDebug = 3; but there is nothing else displaying, and i don’t know where to look.

    Thanks !

    Reply

  11. Hi,
    I cannot log in at mediawiki with this extention.
    Mediawiki version:1.16.1
    extension: (Version 1.2b (alpha))

    output of log:
    2011-02-22 18:34:16 wikidb-mw_: Entering validDomain
    2011-02-22 18:34:16 wikidb-mw_: User is using a valid domain.
    2011-02-22 18:34:16 wikidb-mw_: Setting domain as: tiani-spirit
    2011-02-22 18:34:16 wikidb-mw_: Entering getCanonicalName
    2011-02-22 18:34:16 wikidb-mw_: Username isn’t empty.
    2011-02-22 18:34:16 wikidb-mw_: Munged username: Test
    2011-02-22 18:34:16 wikidb-mw_: Entering allowPasswordChange
    2011-02-22 18:34:16 wikidb-mw_: Entering modifyUITemplate

    anyway – user is created at wiki – i can see the user in userlist but there is no login.
    another user that was created before i added the plugin does work ( this user is in ldap and local wiki with same name and password ).

    any suggestions to this?
    thanks
    arnulf

    Reply

    1. Please use 1.2d. It’s SVN trunk. It’s safe to always use SVN trunk for the LDAP extension, btw. I ensure it’s always in working condition, and is safe to use.

      Reply

    2. Also, I need to see your config options, and the full output of the debug log, with sensitive stuff snipped out.

      Reply

  12. It’s saying you don’t have LDAP support in your PHP installation. I’m not sure which OS you are using, but many have some way of installing it for you.

    Reply

  13. Hi this time with sensitive bits snipped out, could you help with the following? Im getting a “failed to bind” error and not sure what to do? Any help would be great thanks!

    #Ldap Authentication
    require_once(“/opt/app/apache2.2.8/htdocs/aspirewiki/extensions/LdapAuthentication/LdapAuthentication.php”);
    $wgAuth = new LdapAuthenticationPlugin();
    $wgLDAPDebug = 5;
    $wgDebugLogGroups["ldap"] = “/opt/app/apache2.2.8/htdocs/aspirewiki/debug11.log”;
    $wgLDAPDomainNames=array( “domain” );
    $wgLDAPServerNames = array(“domain” => “adserver.domain.net” );
    $wgUseLocal = false;
    $wgLDAPEncryptionType = array(“domain” => “clear”);
    #$wgLDAPProxyAgent = array(“domain”=>”cn=[domain.net],ou=[domain.net],ou=[domain.net],DC=[domain.net],DC=[domain.net],DC=[domain.net]“);
    #$wgLDAPProxyAgent = array(“domain”=>”cn=SVC-CLARITY,ou=Service Accounts,ou=Administrative,dc=domain,dc=net”);
    #$wgLDAPProxyAgentPassword = array(“domain”=>”[domain.net]“);
    #$wgLDAPProxyAgentPassword = array( “domain”=> “SbO512nwDUcv/4aPF+aF”);
    $wgLDAPBaseDNs = array(“OU=[domain.net],OU=[domain.net],dc=[domain.net],dc=[domain.net],dc=[domain.net]“);
    $wgLDAPSearchAttributes = array( “domain.net” => ‘sAMAccountName’);
    #$wgLDAPSearchStrings = array( “domain” => “USER-NAME@domain.net” );
    $wgLdapSearchStrings = array( “domain.net” => “domain\\USER-NAME” );

    Debug Log
    2011-06-30 13:26:30 wikidb: 1.2e Entering validDomain
    2011-06-30 13:26:30 wikidb: 1.2e User is using a valid domain (domain).
    2011-06-30 13:26:30 wikidb: 1.2e Setting domain as: domain
    2011-06-30 13:26:30 wikidb: 1.2e Entering getCanonicalName
    2011-06-30 13:26:30 wikidb: 1.2e Username isn’t empty.
    2011-06-30 13:26:30 wikidb: 1.2e Munged username: Cg10223
    2011-06-30 13:26:30 wikidb: 1.2e Entering userExists
    2011-06-30 13:26:30 wikidb: 1.2e
    2011-06-30 13:26:30 wikidb: 1.2e Entering authenticate
    2011-06-30 13:26:30 wikidb: 1.2e
    2011-06-30 13:26:30 wikidb: 1.2e Entering Connect
    2011-06-30 13:26:30 wikidb: 1.2e Using TLS or not using encryption.
    2011-06-30 13:26:30 wikidb: 1.2e Using servers: ldap://adserver.domain.net
    2011-06-30 13:26:30 wikidb: 1.2e Connected successfully
    2011-06-30 13:26:30 wikidb: 1.2e Entering getSearchString
    2011-06-30 13:26:30 wikidb: 1.2e Doing an anonymous bind
    2011-06-30 13:26:30 wikidb: 1.2e Failed to bind as
    2011-06-30 13:26:30 wikidb: 1.2e with password:
    2011-06-30 13:26:30 wikidb: 1.2e Failed to bind
    2011-06-30 13:26:30 wikidb: 1.2e User DN is blank
    2011-06-30 13:26:30 wikidb: 1.2e Entering allowPasswordChange
    2011-06-30 13:26:30 wikidb: 1.2e Entering modifyUITemplate
    2011-06-30 13:26:35 wikidb: 1.2e Entering validDomain
    2011-06-30 13:26:35 wikidb: 1.2e User is using a valid domain (domain).
    2011-06-30 13:26:35 wikidb: 1.2e Setting domain as: domain
    2011-06-30 13:26:35 wikidb: 1.2e Entering getCanonicalName
    2011-06-30 13:26:35 wikidb: 1.2e Username isn’t empty.
    2011-06-30 13:26:35 wikidb: 1.2e Munged username: Cg10223
    2011-06-30 13:26:35 wikidb: 1.2e Entering userExists
    2011-06-30 13:26:35 wikidb: 1.2e
    2011-06-30 13:26:35 wikidb: 1.2e Entering authenticate
    2011-06-30 13:26:35 wikidb: 1.2e
    2011-06-30 13:26:35 wikidb: 1.2e Entering Connect
    2011-06-30 13:26:35 wikidb: 1.2e Using TLS or not using encryption.
    2011-06-30 13:26:35 wikidb: 1.2e Using servers: ldap://adserver.domain.net
    2011-06-30 13:26:35 wikidb: 1.2e Connected successfully
    2011-06-30 13:26:35 wikidb: 1.2e Entering getSearchString
    2011-06-30 13:26:35 wikidb: 1.2e Doing an anonymous bind
    2011-06-30 13:26:35 wikidb: 1.2e Failed to bind as
    2011-06-30 13:26:35 wikidb: 1.2e with password:
    2011-06-30 13:26:35 wikidb: 1.2e Failed to bind
    2011-06-30 13:26:35 wikidb: 1.2e User DN is blank
    2011-06-30 13:26:35 wikidb: 1.2e Entering allowPasswordChange
    2011-06-30 13:26:35 wikidb: 1.2e Entering modifyUITemplate

    Reply

    1. I believe this thread is also happening on mediawiki.org. I’ll continue helping on there, as LiquidThreads is easier to communicate on than WordPress comments.

      Reply

      1. No Problem, I have updated that thread.

        Thanks.

        Reply

  14. Hi Guys,
    Need urgent help!

    I’m getting (Failed to bind) error and don’t know where I am doing wrong. Below is my LocalSettings.php config.

    $wgLDAPDomainNames = array( “domain” );
    $wgLDAPLowerCaseUsername = array(“domain”=> true);
    $wgLDAPServerNames = array( “domain” => “ldap_server_ip_address” );
    $wgLDAPSearchAttributes = array( “domain” => “uid” );
    #$wgLDAPBaseDNs = array( “domain” => “ou=people,dc=domain,dc=com” );
    $wgLDAPBaseDNs = array( “domain” => “dc=domain,dc=com” );
    $wgLDAPSearchStrings = array(‘domain’ => ‘uid=USER-NAME,ou=groups,dc=domain,dc=com’);
    $wgLDAPEncryptionType = array( “domain” => “clear” );
    $wgLDAPProxyAgent = array( “domain” => “dc=domain,dc=com” );
    $wgLDAPProxyAgentPassword = array( “domain” => “*****” );

    $wgLDAPUseLocal = false;
    $wgMinimalPasswordLength = 1;

    ## Logging Debug-Information for LDAP
    $wgLDAPDebug = 3;
    $wgDebugLogGroups["ldap"] = “/tmp/debugldap.log”;

    Any help would be great appreciated. thanks!

    Reply

    1. $wgLDAPSearchStrings = array(‘domain’ => ‘uid=USER-NAME,ou=groups,dc=domain,dc=com’);

      ^^ That doesn’t look correct. Your users are in your groups ou?

      $wgLDAPProxyAgent = array( “domain” => “dc=domain,dc=com” );

      ^^ That also isn’t correct. This needs to be a user account with enough access to find user DNs.

      Reply

      1. Thanks you your reply.

        I also had used $wgLDAPSearchStrings and $wgLDAPProxyAgent as –

        $wgLDAPSearchStrings = array( “domain” => “uid=USER-NAME,ou=people,dc=domain,dc=com” );

        $wgLDAPProxyAgent = array( “domain” => “dn=Directory Manager,ou=people,dc=domain,dc=com” )
        then,
        $wgLDAPProxyAgent = array( “domain” => “dn=Directory Manager,dc=domain,dc=com” )

        Anything I am doing wrong?

        Reply

        1. dn=Directory Manager,dc=domain,dc=com looks incorrect. You shouldn’t use your directory manager anyway. You should use a proxy agent with limited rights.

          Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>