Automated Coder

Exploring the Code of CruiseControl.Net

Archive for October 8th, 2008

Security Enhancements 1: Display Names

Posted by Craig Sutherland on 8 October, 2008

What’s in a Name?

One of the common uses for security is to retrieve a user name. Since the user has been authenticated, the system can guarentee the person’s name – as opposed to an unsecured system where the name can be anything the client sends.

While the user name is being set and used internaly, this isn’t being passed on to methods like ForceBuild(), AbortBuild() or Request(). It would be nice to use the secure name where possible to guarentee the right name is displayed.

Types of Names

The first issue is display names vs. user names. A user (or login) name is the name that is used for logging in – this will often be a unique name that could also be a code. For example my user name at the university where I used to work was csut017 (also the code for this blog). In contrast my display name was Craig Sutherland – a nice friendly name, but not a guarenteed unique one.

Now I could just use the user name for the display name, but it would be nice to have some friendly names. So the first part of my modification will be to add display names to the authentication. Once I’ve done this, I’ll then look at passing on these display names to the various methods that require a name.

Getting the Display Name

Currently the interface responsible for retrieving the user name is IAuthentication. This has a method – GetUserName() – that will retrieve a user name from a set of credentials. So my first change is to modify this method to also retrieve a display name. This will also take in the credentials and return the display name.

Currently this interface is implemented by UserPasswordAuthentication and UserNameAuthentication. Both these implementations will have a similar process for retrieving the display name. I’ve added a new property called DisplayName that is exposed via a ReflectorProperty attribute (“display”). If this is set in the configuration then it will be returned as the display name, otherwise the user name will be returned.

This will handle the named user scenario, but it won’t handle wildcards. However, since these are both very simple authentication processes, I’m not going to worry about them. More complex authentications can implement different versions of this method.

Storing the Display Name

How that the display name is available it needs to be stored somewhere. This is because credentials are not stored on the server – instead a session is generated and stored, and a session token is used in all future calls.

The interface for caching is ISessionCache. Rather than hard-coding a display name into the cache, I decided to allow multiple values to be stored in a session. To handle this I’ve added StoreSessionValue() and RetrieveSessionValue() methods. These require a session token and a key for the value. The values will be an object to allow for a wide range of possible values.

The only implementation of this interface so far is InMemorySessionCache. Internally this has a struct for storing session details. It is an easy enough task to add a dictionary to this struct that can be used for storing values. The two new methods just use this dictionary internally.

I also did a bit of refactoring. First I changed the struct to a class (although still private). Secondly I added a private method to retrieve an instance of this class from the cache. This also handles expirations – saves me having to copy and paste this functionality with minor changes for the session values.

Now that I have somewhere to store the values, I modified the Login() method in SessionSecurityManager to also store the display name in the cache if the login is successful.

Passing on the Display Name

The final step in this process is to pass the display name onto the required methods. Since the security is handled by the ISecurityManager interface I added a method to allow retrieving the display name from here (yes I decided to hard code it here since it will always be used). ISecurityManager already has a GetUserName() method to retrieve a user name from a session token, so I just added a similar method but for the display name.

ISecurityManager is implemented by NullSecurityManager and SessionSecurityManager. NullSecurityManager always returns null (more on this soon), while SessionSecurityManager will attempt to retrieve a value from the cache. If one is found this will be returned, otherwise null will be returned.

In CruiseServer I modified CheckSecurity() to retrieve the display name if all the checks succeed. This display name is returned from the method so it can be used by the callers.

Finally I modified ForceBuild(), AbortBuild() and Request() to pass on the retrieved display name. If this name is not null or empty, then the received user name is changed to the display name (hence the reason for returning null earlier). And now the secured display name is used for the display name :)

As an added bonus, dashboard requests (either directly or via HTTP protocol from CCTray) will now display an actual user name instead of ‘Dashboard’.

Coming Up

I still have a few idea of additions for security that I’m going to try and do before I go on holiday. These ideas are:

  • Audit logging
  • AD authentication
  • File-based session cache

Plus some more work on the installer and a couple more ideas (which need some more thinking first). I’m not sure how much I’ll be able to do, but if you have any ideas of what could be included let me know and I’ll try and make some time for it.

Posted in CruiseControl.Net, Security | Tagged: | Leave a Comment »