A good practice for mapping TFS collections on local path

How many times did you asked yourself, what now, in front of a very simple question? Then you chose a first thing that came under your mouse? I did it many times! Later this lead me also many times to a problem. One of this banal situations is mapping a local path for a TFS Collections/Projects. Hands up who went creating a directory on C drive and indicating a newly created map as TFS local path! Great, I did the same! However later on, based on experience, I found a way of mapping collections which I believe is a good practice. In the following lines I will share my ideas with you. Any suggestion or observation is welcome, so feel free to comment this post.

Why is not a good idea to just create a folder Projects on a C drive and map everything under it? Well, at first this PC may be used by others, this arise a problem, that can be first of security nature, second can create confusion and problems if the new user chooses the same directory for mapping.

Based on this information, a good place where to store your code is user folder. Generally you can find your user folder in C:\Users\%username% on Vista, 7 and 8, C:\Documents and settings\%username% on XP and 2000. What I follow as a rule is to create a top folder called Projects and then inside that folder a sub folder for every collection I have access to. Supposing that my collection is called ACNProject the full path on my PC looks like C:\Usersmario.FLORES\Projects\ACNProject.

However in some cases this can be a problem. If you are using a roaming profile, you will need to do a couple of tweaks. You must exclude this newly create folder from synchronization and in order to be sure about that, you need to check the following registry key:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ExcludeProfileDirs

You will then find a similar content as on the following image:

Registry editor ExcludeProileDirs key

Now you need to edit this key by adding at the end the folder name that is situated in Users directory, in this case Projects. Different folders are separated by ; sign. If this became a company rule, you can avoid this step by applying the same changes via a group policy.
In case you do not have the rights for editing the registry and you are still using a roaming profile, a good place where to store the files can be C:Documents and settings%username% AppDataLocal which by default is never synced.

Now we are ready to map our collection. Open Visual Studio and Team Explorer.

Team Explorer mapping the collection in Visual Studio

Click on local path and digit the above mentioned path. Make sure that you clicked on collection folder (the $ sign will be visualized as a server folder) and that Recursive check is on. In this way for all the projects in that collection, automatically a folder will be created and mapping will have a recursive effect (all the projects in the collection will be automatically mapped).

Mapping the collection in TFS

Now you will be prompted about getting the latest version of all data from the server, choose no if there are many projects and you need a specific one and then get the latest version of that specific project, otherwise choose yes.

Certainly there can be a case that this approach will not fit, however I consider this a good practice. If you have any suggestions or comments, they are always welcome and I’m always ready to reconsider this task if anything meaningful pops up.

Cheers!

Securing access to the Cisco routers

This article is a translation of my original post written in Italian by the end of 2008 and published on areanetworking.it. As you may know, my working experience and specialized studies have provided me with knowledge and skills in the analysis, implementation, optimization, troubleshooting and documentation of LAN/WAN network systems with strong “hands on” technical knowledge. However in that period I was programming only and it was a long time that I didn’t seriously configured a router. One of my old customers commissioned a configuration of three routers, one in the main office and other two in branches. It was for me something new and challenging because I never before configured fully mashed VPN connection so I wanted to get a bit further and configure also other aspects in a more detailed way. I checked my previous configurations an no one of them satisfied me completely. So I pulled down all the documentation I found and started studying. The following lines are the result of that.

Let´s start, first thing that I did is to separate the virtual terminal lines in two groups, the first one will be reserved for the connections from external networks meanwhile the second will be used for the connections from internal networks. From the external networks will be only possible to connect via SSH where from the internal networks telnet will also be an option.
To achieve this I have given the following commands:

line vty 0 1
line vty 2 4

In this post I will not get in depth about SSH protocol, if you are interested in different version of the protocol, you will find many information’s by Googleing the keywords. If you yet do not know anything about it, it is a way to connect to the terminal where all the data exchanged between client and server are encoded. To achieve that let´s give the following commands:

line vty 0 1
    transport input ssh
line vty 2 4
     transport input telnet ssh

Now we need to make sure that we set up the hostname and the domain name, otherwise, generating the cryptography key will fail. If there is the default hostname set, it would be advisable to change it. Both can be set with the following commands:

hostname MyRouter
ip domain-name majcica.com

Following task is generating the cryptography key base on whom the SSH connection will be secured (will be used to encrypt the data).

crypto key generate rsa

Once you issue this command you will be asked to choose the key size. I will suggest you to leave the default value (512) which is more than enough for 99% of cases. When this operation is over, you will receive the message that SSH is activated and that the current version is 1.5. Unfortunately there is no SSH 1.5 and you may be confused, however this is the way Cisco indicates that SSH version 1 is active. You can always check the current active version by the following command:

show ip ssh

In case it says 1.99 it means that both SSH1 and SSH2 are enabled, meanwhile if the result is 2.0 it means that only the version 2 is enabled.

In order to prevent the access to a virtual terminal interfaces that accepts the telnet connection let’s suppose that our internal network is 10.10.10.024 (10.10.10.x network with a mask 255.255.255.0). Because of that we will create an access list that accepts the traffic only from internal network and block the traffic from all other sources. In order to achieve this is sufficient issuing the following command:

access-list 15 permit 10.10.10.0 0.0.0.255 log

and then apply this access list to a proper virtual terminal interface:

line vty 2 4
   access-class 15 in

If we try now to access the router via telnet from a network that is different than our internal, the request will time out. But if we try to access it from an external network via SSH the router will replay and we will be able to establish a connection.
Next step is setting the time out (60 seconds is a reasonable value), enabling SSH version 2, setting the interface from which route will replay to SSH request (outside interface, in our case are ATM0.1 – ADSL connection) and a maximum authentication retries.

ip ssh time-out 60
ip ssh authentication-retries 5
ip ssh source-interface ATM0.1
ip ssh version 2

Initially I tough that this is sufficient but once I configured logging, I found that, meanwhile testing, there was no trace about the who and when connected to the router. As I believe that this are information’s that we should log, I made a little research and found the following commands:

login on-failure log
login on-success log

First one enable logs on failed attempts meanwhile the second one enables the log on successful log in’s.
Till here everything was fine until couple of days later I consulted the log files and found that someone was attempting brute force log in attacks on my router. I needed a solution for this problem, and limiting the access via ACL was not an option as I often connect to the router via a dynamically obtained IP address. At the end I found that we can set a dynamic block for the users who fails authenticating a certain amount of time in a determinate time interval. Basically if we want to prevent that user receive a response from SSH service for 300 seconds in case he misses the password three times in 30 sec, we need to issue the following command:

login block-for 300 attempts 3 within 30

This for me was sufficient, and it seems a decent practice, however if you feel paranoid you can still change the default SSH port, apply restrictive ACL, etc.
Following you will find an example extract from syslog showing a brute force attack and the quite mode in action.

2009-01-27 08:28:48	Local7.Warning	10.10.10.254	81: 000086: Jan 27 08:28:47.028 Berlin: %SEC_LOGIN-4-LOGIN_FAILED:
Login failed [user: nagios] [Source: 210.192.123.204] [localport: 22] [Reason: Login Authentication Failed]
at 08:28:47 Berlin Tue Jan 27 2009

2009-01-27 08:28:53	Local7.Warning	10.10.10.254	82: 000087: Jan 27 08:28:52.194 Berlin: %SEC_LOGIN-4-LOGIN_FAILED:
Login failed [user: user] [Source: 210.192.123.204] [localport: 22] [Reason: Login Authentication Failed]
at 08:28:52 Berlin Tue Jan 27 2009

2009-01-27 08:28:57	Local7.Warning	10.10.10.254	83: 000088: Jan 27 08:28:57.169 Berlin: %SEC_LOGIN-4-LOGIN_FAILED:
Login failed [user: test] [Source: 210.192.123.204] [localport: 22] [Reason: Login Authentication Failed]
at 08:28:57 Berlin Tue Jan 27 2009

2009-01-27 08:28:57	Local7.Alert	10.10.10.254	84: 000089: Jan 27 08:28:57.169 Berlin: %SEC_LOGIN-1-QUIET_MODE_ON:
Still timeleft for watching failures is 19 secs, [user: test] [Source: 210.192.123.204] [localport: 22]
[Reason: Login Authentication Failed] [ACL: sl_def_acl] at 08:28:57 Berlin Tue Jan 27 2009

2009-01-27 08:33:58	Local7.Notice	10.10.10.254	85: 000104: Jan 27 08:33:57.083 Berlin: %SEC_LOGIN-5-QUIET_MODE_OFF:
Quiet Mode is OFF, because block period timed out at 08:33:57 Berlin Tue Jan 27 2009

I didn’t went in detail on all steps supposing that you have basic knowledge on how to operate on Cisco IOS. All the information’s I got from Cisco.com. Also this procedure where valid by the end of 2008 when the original article was written. However it should not be drastically changed in the newest version of IOS. If so, check the documentation on cisco.com and eventually post your question’s in the comments.

Joyful configuring!

Natural sort order comparison – Part 1

Introduction

One of the things that are at the origin of my passion for programming is the surprise factor. No matter how many experience and studies you make any new assignment brings something new, something not completely explored.
My excursions to the UI are not so frequent and because of that I do not encounter so often some of classical problems that usually are related to UI, in particular sorting cases.
Recently I worked on a project that in UI lists different versions of one well defined entity. The main property of the entity is the version number and it is type of string. Mentioned property, along with others, is shown inside a ListView control. Sorting the list using the standard string comparison was not an option. By using a standard string comparison, numerical part of the string is not treated as a number, instead is treated as a string, which gives that the string “v1.9” comes after “v1.10”. Actually, if we consider a dot as a decimal separator, this is a correct result. However, in our case we need to consider a dot as a major-minor separator and as this we need to treat the minor part as an integer. In order to make the example easier, we will use only major number as version indicator. The entity we are going to list will contain 13 different versions, from “v1” to “v13”. Using a standard string comparison, once we order our list on version field, the result will be the following:

v1
v10
v11
v12
v13
v2

v9

Actually this is correct result if we consider the numbers as ASCII characters, but if we, as usually humans do, would like to consider the numeric part as an integer, this is an undesirable result. What we are expecting to have is the following:

v1
v2

v9
v10
v11
v12
v13

You will find a similar behavior in your Windows Explorer each time you order the files by name.

Now how do we solve this task?

Getting started

In the front of a similar problem, I don’t like just to Google a couple of keywords and use the first solution that appears on the search list. Also, the application is flexible enough so we can easily encounter different user settings and the sorting requirements may change. In order to see a bigger picture I decided to explore this area a bit more in detail.
At the end I found two viable approaches to this problem

  • Using a StrCmpLogicalW function via P/Invoke
  • Writing a custom class that implements IComparer interface and a custom comparison algorithm
    Both methods are valid, each one with its own pros and cons. So let’s see them both in detail.

StrCmpLogicalW via P/Invoke

Inside the shlwapi.dll you will find a method called StrCmpLogicalW, which, as said in method’s description, “Compares two Unicode strings. Digits in the strings are considered as numerical content rather than text.”. This is a pretty handy method, it is easy to implement and it is fast. However it has couple of cons that can make you choose different approach, as example it shows different behavior on Windows XP instead of Windows Vista. Also it is not implemented in Windows 2000 and numerical content is always treated as integer. However, it is very unlikely that you will find yourself in any of listed situations and that the standard functionalities offered by StrCmpLogicalW will be a limitation.

The implementation

For the less experienced programmers, I will show a decent way to create a class that implements IComparer interface and uses the StrCmpLogicalW class in order to calculate the comparison result.
As first we should declare a helper class that will make the calls to the StrCmpLogicalW easier.

[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    public static extern int StrCmpLogicalW(string psz1, string psz2);
}

Actually there is not a lot to say about this class. It is an internal (the class can be accessed by any code in the same assembly, but not from another assembly) and is declared as static (indicating that it contains only static members). SuppressUnmanagedCodeSecurity attribute is primarily used to increase performance, for further details consult the following page http://msdn.microsoft.com/en-us/library/ms182311(v=vs.80).aspx.
Now we have all the necessary in order to implement the following class

public sealed class NaturalOrderComparerNative : IComparer, IComparer
{
    public int Compare(string a, string b)
    {
        return SafeNativeMethods.StrCmpLogicalW(a, b);
    }
 
    public int Compare(object x, object y)
    {
        string a = x as string;
        string b = y as string;
 
        return Compare(a, b);
    }
}

Implementing the IComparer interface is straight forward as it requires only Compare method to be coded. Compare method has the following signature public int Compare(object x, object y), it compares given objects and returns a value indicating whether first is less than, equal to, or greater than the second one. In case that x is less than y it will return -1, if x equals y will return 0 (zero) and in case x is greater than y will return 1.
I also implemented a generic version of this interface, IComparer. I think that there are no more explanations to do about this small piece of code. If not, just comment under the article and I will try to do my best in order to make this clear.
So let’s summarize:

PROS CONS
Performances Platform dependent
Simple implementation Non customizable
Proven algorithm

In the second part of this article (blog post) we will see how to implement a custom algorithm and some usage examples, together with full source code in C# and VB.

Follow us so you can be notified about the new posts.