Automated Coder

Exploring the Code of CruiseControl.Net

Archive for July, 2009

Monitor – a High Level API

Posted by Craig Sutherland on 18 July, 2009

Introduction

Recently I’ve been playing around with some client applications for CruiseControl.NET (more on this in a later post). As I was coding, I realised it is not that easy to work with entities for CruiseControl.NET. Yes, there is a new communications library that simplifies the communications, but it still requires a knowledge of which method does what.

It would be nice if there were some high level entities that simplify this process and hides all the method calls. Additionally, it would be nice if these entities stayed up-to-date with the actual server. This would be useful in a number of places – including both CCTray and the dashboard.

So I sat down and put together a high level API. This is built on top of the communications library – so under the hood it just uses the messaging. But it does abstract away these details – instead of calling the communications API and passing in the correct parameters, you just initialise the Monitor API and then use the entities returned.

Before I continue, I should mention, this is my first cut of it. I have been trialling it out and it “kind-of” works, but it is still very rough around the edges. Of course, this will only be relevant to you if you are interested in developing applications to communicate with the CruiseControl.NET server.

The API

The API exposes four entities (currently):

Monitor Classes

These classes expose most of the information about the current status of the server. When I say current, I mean as of the last snapshot taken of the server. They don’t include historical details (yet).

The Server class provides a high-level overview of the server. Currently, this only lists the projects and the servers that are available, but it does provide notifications of when projects or queues are added or removed from the server. Additionally, this is the root level class for the API. To interact with the API you will need to create an instance of this class – more on this later.

The Project class provides details on the current status of a project. This is all taken from the snapshot method, so it doesn’t include historical details. It does contain all the details that are currently available in CCTray or the projects grid of the dashboard (e.g. current status, current activity, next and previous build times, etc.)

The BuildQueue class does the same for an integration queue, although there are less details available for a queue. It does expose an array of BuildQueueRequest instances, which contains details on each current or pending request for the queue.

These four classes are all tied together, which eliminates some of the problems we have in CCTray. For example, in the Module API, it is easy to find out which server a project belong to, as there is a direct relationship between the two (Project has a property called Server, which points to the Server instance).

Additionally, there are a number of helper methods (with more to come). If you need to build a project, there is a method called ForceBuild() which does exactly that. under the hood, these methods call the communications API to pass the requests onto the server, but someone using the Monitor API does not need to know this.

Events and Monitoring

One of the key parts of the Monitor API is change notifications. The API can be configured so it automatically monitors the server (hence the reason for its name). When the server changes (e.g. adding/removing a project/queue, a project starting building, etc.) an event is triggered.

Most of the classes implement INotifyPropertyChanged, so a PropertyChanged event will be fired when a property on the server changes. There is also a new set of events for when a project, build queue or build queue request is added or removed.

This makes it easy for a client to detect any changes – just initialise the Server instance with a polling watcher and the events will be fired automatically. This makes it incredibly easy to set up applications that “watch” a server and do things when the server changes.

Some Examples

Rather than go into the details of how the API works, I thought I’d finish off with some examples so people can see how it works.

First of all, to initialise the API, a new server instance needs to be created. Since this relies on the communications API underneath, it needs an instance of CruiseServerClientBase. The following shows how to initialise  the client and then the server:

  1: var client = factory.GenerateClient(clientAddress);
  2: var server = new Server(client);
  3: server.Refresh()

The first line creates the new client instance, the second then creates the server instance. The third line is not strictly necessary, but it will force a refresh of the data from the server (otherwise it will wait until the server is polled).

Once the server is initialised, it is easy to work with both projects and queues. There are both Projects and BuildQueues properties to list all of the projects and queues. Alternately, if you know which project or queue is needed, there are FindProject() and FindBuildQueue() methods to search by name. For example, to force a build on a project you could use the following code:

  1: var project = server.FindProject("CruiseControl.NET");
  2: project.ForceBuild();

Finally, here is an example of how to register an event for watching a status change:

  1: var project = server.FindProject("CruiseControl.NET");
  2: project.PropertyChanged += (o, e) => {
  3:     if (e.PropertyName == "Status") {
  4:         // Do something for a status change
  5:     }
  6: };

And for a new build request on a queue:

  1: var queue = server.FindBuildQueue("CruiseControl.NET");
  2: queue.BuildQueueRequestAdded += (o, e) => {
  3:     // Do something when a new build request is queued
  4: };

Of course, these are just some of the things that can be done, plus I should mention that there are still a lot of things that cannot be done (at least not directly).

Where To Next?

Over time I’m planning on expanding the API to cover a lot more tasks. Initially I plan on including all the information and tasks that are available in CCTray 1.5.0. Most of this has already been done, but I still need to include status breakdowns and package lists.

Once this is feature complete, I’ll start looking at how to include historical data – previous build results, history and statistics, etc. This will cover most of the information that is available in the dashboard.

At the same time I am working on a little side project that is using the new Monitor API. This has mainly been a test bed for concept, which I’m looking at releasing as a separate project (more on this later on).

Once the API is complete and useful, I might (and I’ll stress the “might” part) convert both CCTray and the dashboard to use it. This would certainly simplify a lot of the “horrible” code in these two clients. The bad news is it getting harder to work with these two clients, and trying to unwind all the complexities around communications is challenging (hence the reason for some of the existing bugs!)

In Conclusion

Hopefully, this gives an idea of what can be done with the new Monitor API, and also some of its current limitations. Over time I’m planning on expanding it to provide any necessary information from CruiseControl.NET, by which time it should be easy to build clients for the system.

And finally, I have a surprise coming, although it’s not completely new news.

Stay tuned…

Posted in CruiseControl.Net | Tagged: | 2 Comments »

The Missing Piece: Encrypted Communications

Posted by Craig Sutherland on 15 July, 2009

Introduction

In my last post (read it here) I wrote about an issue with security – that the actual communications between the client and the server were not secure. I also outlined the approach I was taking to remedy the issue.

Before I move onto my solution, I must mention that this is not a perfect solution. As one of my readers commented, this does not really cover a man-in-the-middle attack. It will prevent network sniffing and replay attacks, it is still possible to insert a listener between the client and the server.

It is possible to configure .NET Remoting to intrinsically secure communications – in which case there is no need to worry about this from the client side at all. However, it is not easy easy as it might appear, so I decided to finish my partial solution.

In time, I hope to be able to look at expanding the communications channels. Currently the only channel for communicating with the server is .NET Remoting – which was because of the way methods used to be called. Now with the new messaging-based framework, it is easier to add new channels. Hopefully I will get some time to look at using SslStream and NegotiateStream to secure communications.

Client Communications

First, how does the new code send encrypted messages to the server? This involved expanding how messages are currently sent.

Currently messaging uses the following model:

Communications

Using the new communications model, each client application will generate an instance of a CruiseServerClient. Actually they generate a CruiseServerClientBase instance, but the class that implements this abstract class for the new framework is CruiseServerClient. This class does not actually send any messages – instead it translates the method calls (e.g. ForceBuild) into messages (e.g. ProjectRequest), sends the message and then processes the response.

The actual sending is done by an instance of IServerConnection. This instance takes the specified messages and pushes them over the specified channel (either .NET Remoting or HTTP). Because the actual channel is encapsulated by an IServerConnection, it is easy to replace the channel with a different one.

For encrypted communications I added a new channel called EncryptingConnection. This channel is then inserted between the client and the underlying communications channel:

EncryptedCommunications

This means that the messages are encrypted (both ways), but the underlying transports (e.g. HTTP or .NET Remoting) can still be used without any changes.

There are a couple of extra changes. First, the original request message gets replaced by an EncryptedRequest message. This contains the original message, but encrypted (of course), and the original action that was requested. Secondly, the action has been changed to ProcessSecureRequest – more on this when I cover the server side changes.

EncryptingConnection is also responsible for the hand-shaking required to set up the encrypted communications. When a message is sent, the connection checks to see if it has a password. If it does not have a password, sets up a new common password by the following process:

  1. Ask the server for its public key
  2. Generate a new secret (using RijndaelManaged)
  3. Encrypt the secret using the server’s public key (using RSACryptoServiceProvider)
  4. Send the secret to the server and wait for the response
  5. Store the secret locally

Once this has been done, all messages are then encrypted using the common secret (again with RijndaelManaged). This includes both request and response messages.

The actual sending of the messages is then done by passing the message onto the underlying channel.

Server Communications

Now that the client can send messages, we need to look at the server side. After all, if the server can’t understand the messages, then nothing will be done!

All communications into the server come in via CruiseServerClient. This is a MarshalByRefObject-derived class that uses .NET Remoting. All HTTP communications actually go via the dashboard, which passes them onto the server using .NET Remoting. So this model simplifies things – I only need to change CruiseServerClient!

Currently CruiseServerClient has one overloaded method for processing messages – ProcessRequest(). This takes the incoming message, works out which method to call, converts the message into the required objects (if required) and then calls the method. It also handles generating the response and adding any error information.

To handle secure messages I have added a ProcessSecureRequest (). This method is called by ProcessRequest() and acts as a middle-man. Basically, when ProcessRequest() gets a secure message, it passes it onto ProcessSecureRequest(), which then works out which methods to call, converts the message, etc.

I have also added three other new methods:

  • RetrievePublicKey() – this will send the server’s public key to the client. If the server does not have a public/private key pair it will generate the pair (using RSACryptoServiceProvider).
  • InitialiseSecureConnection() – this receives the common secret from the client, decrypts it and stores it locally.
  • TerminateSecureConnection() – this will remove the common secret for a client from the local store.

These methods are called as part of the hand-shaking between the client and the server.

Additionally, as part of these changes, I have added a new property to the messages called ChannelInformation. This property has information on how the message was transported – i.e. metadata about the message itself.

Currently, there is only one implementation – RemotingChannelSecurityInformation. This says the messages was transported using .NET Remoting. On this class is a property called IsEncrypted. ProcessRequest() generates an instance of this class and sets IsEncrypted to false, while ProcessSecureRequest() generates an instance with IsEncrypted set to true.

Turning On Encryption

Encryption is turned on from the client-side. When a client wants to communicate with a server using encrypted communications, they need to set UseEncryption to true in ClientStartUpSettings.

Currently, this is not possible with the dashboard, but I have added it to CCTray. When a new server connection is added (for either .NET Remoting or via the dashboard), there is a new option of turning on encryption:

CCTray Encryption

To use encrypted communications, all that is needed is to check this box.

Unfortunately, due to the way CCTray is configured, it is not possible to turn on encryption for an existing server. Instead the server needs to be removed and re-added (yuck!) This is probably a good area for tidying up in a future release of CCTray.

Enforcing Encryption

All this work so far has been to set up encrypted communications. At this point, it is up to the client to decide whether the channel is encrypted or not – the server doesn’t really care. We need some way of telling the server to only accept encrypted communications (i.e. to enforce encryption).

To do this, I have added a new configuration option to the server security settings – channel. This is an optional setting and has one required property – the type of channel. The following shows how to configure a channel to use encrypted messages:

  1: <internalSecurity>
  2:   <channel type="encryptedChannel"/>
  3:   <users>
  4:     <!-- Omitted for brevity-->
  5:   </users>
  6:   <permissions>
  7:     <!-- Omitted for brevity-->
  8:   </permissions>
  9: </internalSecurity>

This tells the security manager it will only accept communications over an encrypted channel.

When a message is received by the message processer (i.e. after it has been received by CruiseServerClient, processed and passed on), it calls a method called ValidateRequest(). This does some simple validation checks (the message is less than a day old and it hasn’t been duplicated). I have expanded this validation check to detect a channel definition and if present to validate it.

The Basics Of Encryption

This provides some of the basic pieces for encrypted communications. It certainly is not a comprehensive solution – there are still some areas uncovered (like validating the server is who it says it is).

In terms of where this can go, there are the following items that can be included:

  • Additional encryption mechanisms (e.g. DES, triple DES, AES, etc.)
  • Additional security channels (e.g. SSL, negotiated)
  • Validation of the server (perhaps via X.509 certificates)
  • Use encryption from the dashboard

But this provides a start. Let me know what you think so far.

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

One More Piece of the Puzzle

Posted by Craig Sutherland on 9 July, 2009

Security is Not Quite Finished…

Way back when I started on security for CruiseControl.NET, I wrote about a number of different areas that needed to be covered. Since then, I have completed most of them. Most, but not all…

One area that I originally wrote about was “man in the middle” attacks. To understand this attack, we need to step back first and look at the parts of CruiseControl.NET. CruiseControl.NET can be divided into two general parts: the server and a client.

The server is the heart of CruiseControl.NET, it performs the builds, checks the source control repository, etc. The client is a remote connection to the server, that a user can interact with – which can be either CCTray or the web dashboard. The client generally communicates with the server over a network:

Client-Server

Now, unless both the server and the client are on the same machine, this opens the possibility of a “man in the middle” attack. Generally, we assume that the message goes from the server to the client or vice-versa over the network without anything in between. But, this does not have to be the case. Instead, a third party can position itself in between:

Min-in-the-Middle

In this scenario, all messages go through the third party, allowing potential malicious use of the system. Alternately, the third party could just monitor the traffic, such as with a network sniffer:

Sniffer

Either way, it is now possible for a third party to see and interact with the messages that are passed. As the messages could contain sensitive information (e.g. passwords and login credentials) or can control the server (e.g. start/stop projects, force/abort builds, etc.), we don’t particularly want a third party in between!

Now, people might say this is not an issue for them, but unless you can guarantee a secure network (or both the client and server are on the same machine), you are vulnerable to this type of scenario.

What Can be Done?

Before I look at what can be done, let’s look at why this attack can happen. When either the server or the client wants to communicate, they generate a message to send. This message is plain old text (well, actually XML, but close enough). This means there are open messages flying around the network:

Messages-Plain

Anyone can look at these messages and/or change them, and neither the client or the server would be any wiser. Actually, this isn’t just an issue with CruiseControl.NET, this is an issue with any communications over a network, like any HTTP traffic over the Internet. Any pages that are browsed via http:// are sent plain text. This is where https:// comes in – it secures the messages that are passed. The question is, how is this done?

The answer is very secure – each and every message is encrypted:

Messages-Secure

Since the messages are no longer plain text, any third party in the middle cannot read or modify them. A nice simple solution to the problem. But, like anything, things are never quite that easy!

In order for each side to understand the messages, there needs to be a common understanding – messages are using this form of encryption with this password. Now, with https:// the browsers handle this for you automatically (or almost automatically), so there is no need for user interaction. However, for CruiseControl.NET, nothing like this exists, so it will be my task to build it.

Reaching an Agreement

Now I’m not a cryptographer, so this post will simplify things (a lot!) But here is my basic plan of attack. For encryption there are two basic types – symmetric and asymmetric.

Symmetric is where both sides share a common secret (e.g. a password) and they both use this secret for encryption and decryption. Asymmetric is where there are two secrets – one is used for encryption and the other for decryption. A message encrypted with one secret cannot be decrypted with the same secret – it needs the matching secret to be decrypted.

This means one secret can be common knowledge – typically called a public key. Anyone can encrypt some data using the public key, and nobody can read that data unless they have the other secret – commonly called the private key. In our case, the server will have a public/private key pair. Any client can request the public key and use it to encrypt data to send to the server.

However, this plan has two problems. First, this only works for sending data to the server. Since anyone can access the public key, they could decrypt any data being sent back to the client. This can be resolved by giving the clients public/private key pairs as well, but now the server has a lot more work tracking which public key is needed for which client! The second problem with with asymmetric encryption in general – it is a more expensive (and hence slow) operation to perform than symmetric encryption.

There is a common solution to these two issues – combine the two types of encryption. When a client first connects to the server, it requests the server’s public key. Since this is public knowledge, there is no security hole. The client then generates a secret, encrypts it with the public key and passes it back to the server:

Handshaking

Since the password is encrypted with the public key, only the server with its private key can decrypt it – again no security hole. All subsequent communications between the server and the client then use symmetric encryption with the common secret – a much less expensive form of encryption. The server still needs to keep track of all the password, but it means the client doesn’t need both a public and a private key, so there’s a bit of a gain.

How Is This Done?

That’s the basic theory of things – you now know I’m going to implement encryption on the messages to secure them. This will prevent a third party from either reading or modifying any messages. This will use a public/private key pair on the server to set up a common secret between the two, with all subsequent communications using symmetric encryption.

The basic process will be something like this:

  1. Client requests public key from server
  2. Server sends public key
  3. Client generates secret, encrypts it with the public key and sends it to the server
  4. Server sends a confirmation
  5. Client and server then exchange messages with symmetric encryption

Nice and simple. But there are some catches:

  1. Not everyone will want to use this
  2. Someone can still pretend to be the server
  3. Needs to be extendable

Catch #1 can be set at both the server and the client sides, with the server having the ultimate say. If the server does not return a public key, then steps 2-4 will be skipped and the messages will be passed in plain text. The client can also skip straight to step 5 and just pass messages in plain text. However, the server will have a setting to enforce encryption – i.e. if the client attempts to send plain text messages and the server does not like them, they will be rejected!

Not sure on how to handle catch #2 yet – but I imagine this can be done by checking a hash. The server would generate a hash using its private key and the client would then decrypt it using the public key – thus verifying the server is who it says it is. This would require some external way of passing the public key though.

Catch #3 is fairly straight-forward – I will expand the server security configuration to include this. Each encryption method will be configurable – and people can add their own if they wish.

Anyway, that’s enough for tonight. I’ve got my general plan, in my next post I’ll go into details on how this will be implemented.

Stay tuned…

Posted in CruiseControl.Net, Security | Tagged: , | 3 Comments »

Migration Wizard

Posted by Craig Sutherland on 6 July, 2009

I have completed the first cut of the migration wizard. This wizard is now included in the installer – screenshots on how this looks are available here.

The wizard will migrate the following items when converting from 1.4.3 or 1.4.4:

  • State and log files on the server are moved to ProgramData for both the console and the service
  • E-mail groups configuration changed to use multiple notification types instead of a single attribute
  • Dashboard configuration and packages are moved to ProgramData

The wizard will migrate the following items when converting from 1.4.2 or older (up to 1.4.0):

  • Convert statistics file so it doesn’t cause double tabs
  • Plus all the above migrations from 1.4.3/1.4.4

At the moment, I have only tested this on Windows machines – this will probably fail on *nix-based machines due to the slightly different folder structure.

Let me know if there are any issues.

Posted in CruiseControl.Net | Tagged: , , | 5 Comments »