tag:blogger.com,1999:blog-51273895720855949322024-03-13T08:59:21.057-05:00Distributed FrostbiteTechnology from the vast, open plains.zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-5127389572085594932.post-7501951663097055282013-03-14T20:28:00.000-05:002013-04-09T16:06:24.920-05:00Stopping Development of WinRM for Ruby<hr />
<b>UPDATE:</b> <i>Paul Morton has graciously volunteered to take over the helm and continue development on WinRM. I hope to be involved again in the future but Paul has been a great help in the past and I have a great deal of faith in his ability to move WinRM forward. Here's a link to the new repository: <a href="https://github.com/WinRb/WinRM" target="_blank">https://github.com/WinRb/WinRM</a></i><br />
<hr />
<br />
It's with much reluctance that I announce the end of development for the <a href="https://github.com/zenchild/WinRM">Ruby WinRM</a> gem. It's always hard to say goodbye to a project especially one like WinRM. I've invested countless hours on it and it has put me in touch with some very great people in the Ruby and Open Source communities. I also had the privilege to work directly with some of the Microsoft staff early on when I was trying to figure out the protocol and they were a complete class act. It made this life-long UNIX admin eat his words (at least for a short while).<br />
<br />
The reason for my departure from the project is simply that I no longer have access to all of the infrastructure for testing. There are a lot of issues that come in that I no longer have the means to test easily. When I was employed with the State of North Dakota we actually used the code so it was easy to test fixes that came in. I also had some excellent Beta testers that caught most issues, thanks <a class="g-profile" href="https://plus.google.com/104593507680698067010" target="_blank">+Robert Hart</a>.<br />
<br />
The code will remain on Github at <a href="https://github.com/zenchild/WinRM">https://github.com/zenchild/WinRM</a> and it is licensed under the Apache 2.0 license so have at it. If you have questions about the code or want to pay me a handsome sum for extending it please reach out.<br />
<br />
Until then - Cheers!zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-66588000104900314312010-12-23T11:26:00.000-06:002010-12-23T11:26:46.249-06:00Creating a Kerberized client/server app in Ruby with GSSAPIIt's been awhile since I posted anything so I thought I'd write a little bit about the <a href="https://github.com/zenchild/gssapi">GSSAPI Ruby gem</a> that I have been working on recently. GSSAPI and Kerberos are probably the biggest things I've longed for in Ruby for some time now. I work in an Enterprise environment for the State of North Dakota and we use Active Directory authentication for most everything. Since AD has Kerberos built-in, it opens a lot of options for authentication and encryption. I wanted to bring this functionality into the Ruby world so I wrote a gem that utilizes FFI and the underlying GSSAPI C libraries to do exactly that. Since the <a href="http://web.mit.edu/kerberos/">MIT Kerberos</a> source comes with a <a href="http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/gss-sample/">sample client and server</a> application I thought I would create a simple duplication of that in Ruby.<br />
<br />
<h1>The Client</h1>GSSAPI/Kerberos relies on a Service Principal Name(SPN) on the server. We specify it in the client code so that is why I mention it here. If you were creating an actual server for production you would want to create a separate SPN for it, but since this is a demo I will be using the 'host' SPN which should exist by the mere fact that the server is part of the Kerberos Realm. To run the client you will also need to have credentials of your own via 'kinit'.<br />
<br />
Require the appropriate gems.<br />
<blockquote>require 'gssapi'<br />
require 'base64'<br />
require 'socket'<br />
</blockquote><br />
Specify the server and the service name. Together these become the SPN.<br />
<blockquote>host = 'example.org'<br />
service = 'host'<br />
</blockquote><br />
Open up the connection to the server<br />
<blockquote>sock = TCPSocket.new(host, 8082)<br />
</blockquote><br />
Initialize the GSSAPI security context and Base64 encode it so it is ready for transport. The Base64 encoding is not really necessary in this case, but since GSSAPI is often used in HTTP communication and is Base64 encoded there I am using it in this example. The GSSAPI::Simple wrapper is doing a lot in the background for you. It's importing the SPN for use in GSSAPI string types, managing memory and all of that good stuff. If you need to do something a bit out of the ordinary with GSSAPI and need to call the gss_* methods directly, check out the <a href="https://github.com/zenchild/gssapi/blob/master/lib/gssapi/simple.rb">Simple wrapper</a> for examples.<br />
<blockquote>cli = GSSAPI::Simple.new(host, service)<br />
tok = cli.init_context<br />
stok = Base64.strict_encode64(tok)<br />
</blockquote><br />
Send the initial token, get back a response token and complete the security context. Once this step is done the set-up is complete and we are ready to start passing messages.<br />
<blockquote>sock.write("#{stok}\n") # send initial token<br />
stok = sock.gets.chomp # get back continuation token<br />
ctx = cli.init_context(Base64.strict_decode64(stok.chomp)) # complete security context<br />
puts "Connection #{(ctx ? 'succeeded' : 'failed')}"<br />
</blockquote><br />
Now just prompt for text from STDIN, encrypt the message and send it to the server. Do this until "exit" is typed on the command line.<br />
<blockquote>begin<br />
print "> "<br />
msg = STDIN.gets.chomp<br />
emsg = cli.wrap_message(msg)<br />
sock.write("#{Base64.strict_encode64(emsg)}\n")<br />
end while msg != 'exit'<br />
<br />
sock.close<br />
</blockquote><br />
<h1>The Server</h1><br />
Set up is the same.<br />
<blockquote>require 'gssapi'<br />
require 'base64'<br />
require 'socket'<br />
</blockquote><br />
The host and service should be the same as the client as well.<br />
<blockquote>host = 'example.org'<br />
service = 'host'<br />
</blockquote><br />
You won't always want to run as root so the system keytab may not be available. You can specify an alternate keytab as long as it contains the correct SPN.<br />
<blockquote>keytab = "#{ENV['HOME']}/.gssapi/krb5.keytab" # this is optional, but probably required if not running as root<br />
</blockquote><br />
Start listening....<br />
<blockquote>tcpsrv = TCPServer.new(host, 8082)<br />
</blockquote><br />
Initialize the security context for the server and acquire the credentials from the keytab.<br />
<blockquote>srv = GSSAPI::Simple.new(host, service, keytab)<br />
srv.acquire_credentials<br />
</blockquote><br />
Start the main server loop. This will listen for incoming requests, accept the incoming token, and send back a token so the client can complete the security context. After that it just listens for messages, decrypts them and prints them out. It will exit when it receives the "exit" message.<br />
<blockquote>loop do<br />
Thread.start(tcpsrv.accept) do |s|<br />
print(s, "Accepted Connection\n")<br />
stok = s.gets.chomp<br />
print(s, "Received string#{stok}\n")<br />
otok = srv.accept_context(Base64.strict_decode64(stok.chomp))<br />
s.write("#{Base64.strict_encode64(otok)}\n")<br />
<br />
begin<br />
emsg = s.gets.chomp<br />
msg = srv.unwrap_message(Base64.strict_decode64(emsg.chomp))<br />
puts "Received: #{msg}"<br />
end while msg != 'exit'<br />
<br />
print(s, "Closing Socket\n")<br />
s.close<br />
end<br />
end<br />
</blockquote><br />
That's really it and it's much shorter and easier to understand than the C counter-part. If you have issues running it make sure you have your credentials on the client (kinit) and the server has access to the appropriate keytab. These are the two big follies that will mess things up. Other than that have fun with the gssapi gem. If you use it and want to share, add your app to the gssapi gem wiki: <br />
<a href='https://github.com/zenchild/gssapi/wiki/Users-of-GSSAPI'>https://github.com/zenchild/gssapi/wiki/Users-of-GSSAPI</a><br />
<br />
Cheers and Happy Solstice!zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com7tag:blogger.com,1999:blog-5127389572085594932.post-89390020933844968802010-09-24T11:24:00.002-05:002010-09-24T11:26:09.600-05:00Connecting to Windows from Capistrano with WinRMAfter developing the <a href="http://distributed-frostbite.blogspot.com/2010/08/managing-windows-with-ruby-part-1-or.html">WinRM</a> library for Ruby I thought about what uses it may have. One thing I had longed to put to use in the enterprise is a tool like <a href="http://capify.org/">Capistrano</a>. It has long worked well in the UNIX world where every system really should be running SSH, but installing SSH on every MS Windows system enterprise-wide really isn't realistic in many cases. That's when I began to experiment in integrating WinRM into Capistrano. The goals were simple:<br />
<br />
<ol><li>Do not require the user to patch Capistrano.</li>
<li>Make the usage of WinRM in the Capfile as seamless as possible.</li>
</ol><br />
To accomplish what I wanted I had to override some methods within Capistrano to inject WinRM functionality. The end result adds a <b><i>winrm</i></b> command that should work almost identical to Capistrano's own <b><i>run</i></b> command. It should also allow your current Capfile to run unmodified if you do not have any winrm tasks.<br />
<br />
To define a WinRM task you can simply do this:<br />
<br />
<script src="http://gist.github.com/595481.js?file=capfile_simple.rb">
</script><br />
<br />
<b><i>winrm</i></b> also supports using blocks just like <b><i>run</i></b> so you can format your output a bit better like so:<br />
<br />
<script src="http://gist.github.com/595487.js?file=capfile_extended.rb">
</script><br />
<br />
There you have it. As long is WinRM is configured on the remote Windows systems you can now manage them with your Capistrano infrastructure. There is a gem up on <a href="https://rubygems.org/">Rubygems</a> that adds in the functionality so just do a:<br />
<b>gem install -r capistrano_winrm</b><br />
<br />
The source code for this extension is also up on Github:<br />
<a href="http://github.com/zenchild/capistrano_winrm">github.com/zenchild/capistrano_winrm</a>zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com3tag:blogger.com,1999:blog-5127389572085594932.post-27702819107706764532010-08-19T11:54:00.000-05:002010-08-19T11:54:29.852-05:00Managing Windows with Ruby (Part 1) or...<h1>How I learned to stop worrying and manage Windows from Linux</h1><br/><br/><br />
<h1>Intro to Windows Remote Management</h1><p>I have long been a UNIX guy and have always struggled living in a mixed OS environment. Traditionally Windows based systems have made it very hard to do things remotely from systems other than other Windows boxes. This is where Microsoft's implementation of the WS-Management Protocol comes into play. The newer versions of the OS (2003 R2, Vista, 2008, and Win7) all allow you to turn on Windows Remote Management (WinRm). This is a major step forward for heterogenious envirnments because WinRM communicates over HTTP and SOAP. For more information as well as instructions on how to configure WinRM, please visit Microsoft's <a href="http://msdn.microsoft.com/en-us/library/aa384426(v=VS.85).aspx">WinRM site</a>. If you would like to follow along and read the WinRM docs later you can simply open up an Admin Powershell and issue the following:<br />
<blockquote>winrm quickconfig<br />
</blockquote>This will create an HTTP listener on port 5985 by default. I still recommend that you read the docs for more information.</p><p>Once WinRM is configured and listening the hard part is really over. Now all we need to do is pass SOAP packets back and forth in order to tell the remote Windows box what we want it to do. I have created a Ruby library called <a href="http://bit.ly/ruby_winrm">'winrm'</a> that aids in the building and parsing of the SOAP packets so all you have to do is call your <a href="http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx">Powershell</a> or run your <a href="http://msdn.microsoft.com/en-us/library/aa394606(VS.85).aspx">WQL</a> and go.<br />
</p><br />
<h1>WinRM for Ruby Set-up</h1><p>Before diving into the examples WinRM for Ruby needs a little set-up. First and foremost the gem needs to be installed. It is up on <a href='http://rubygems.org/gems/winrm'>Rubygems.org</a> so you can just do a:<br />
<blockquote>gem install -r winrm</blockquote>Every program that uses WinRM will have to set-up the following:<br />
<blockquote>WinRM::WinRM.endpoint = 'http://mywinhost:5985/wsman'<br />
WinRM::WinRM.set_auth('user','pass')<br />
winrm = WinRM::WinRM.instance<br />
</blockquote>The 'winrm' instance created on the last line will be used in the following examples.<br />
</p><h1>Running Powershell scripts</h1><p>Powershell has a nice little option called '-encodedCommand' that lets you run a Base64 encoded script. Because of this it is relatively simple to write Powershell scripts locally and run them remotely with WinRM. To do this with the Ruby library you can simply issue<br />
<blockquote>winrm.powershell(script_file)</blockquote>This will return an array in the form [stdout, stderr].</p><p>Just to clarify, these scripts are local to the machine running the WinRM for Ruby library. That means you can store them on your Linux desktop or wherever you store your scripts and run them from there.</p><br />
<h1>Running WMI Queries (WQL)</h1><p>WMI is invaluable when enumerating system information from a Windows system. One way at getting values out of WMI is via <a href="http://msdn.microsoft.com/en-us/library/aa394606(VS.85).aspx">WMI Query Language (WQL)</a>. WQL is SQL-like in syntax and very easy to use. The WinRM Ruby library implements this feature with the WinRM::WinRM#wql method. You can issue WQL queries like this:<br />
<blockquote>winrm.wql 'select * from Win32_Service'<br />
</blockquote>This method will return an Array of Hashes. Each Hash will contain the name/value pairs retrieved from WMI. For instance, if your WQL was<br />
<blockquote>'select Name,Status from Win32_Service'</blockquote>your return would look something like this:<br />
<blockquote>[<br />
{'Name' => 'Appinfo', 'Status' => 'OK'},<br />
{'Name' => 'Browser','Status' => 'OK},<br />
...<br />
]<br />
</blockquote></p><br />
<h1>Give it a try...</h1><p>That's a quick overview of how to use WinRM. It's a very new library so enhancements will be coming and I hope to have a Part 2 to this post that discusses the actual SOAP protocol that WinRM uses. In the meantime, give it a try and let me know how you're using it in the comments. You can also clone the source on github or open an issue on Github if you run into any issues.<br />
</p><br />
Github: <a href="http://bit.ly/ruby_winrm">http://github.com/zenchild/WinRM</a><br />
<br />
Cheers!zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-25353409710320903892010-08-02T12:06:00.000-05:002010-08-02T12:06:46.612-05:00Viewpoint for Exchange Web Services - Next Generation BETAI would like to announce the next generation, BETA release of <a href="http://bit.ly/viewpoint_ews">Viewpoint</a>, my Exchange Web Services client library for Ruby. This release has some major changes from the previous one which I'll list below. It was also developed in Ruby 1.9.x and the RSPEC tests have also completed in Ruby 1.8.7. There is much work that needs to be done adding features to the Model, but the SOAP guts have been hashed out fairly well in my mind and adding features from here on out should be fairly incremental. So without further ado, here are some of the major changes found in this BETA release.<br />
<br />
Check out the latest code from the <a href="http://bit.ly/viewpoint_ews">Viewpoint Github repository</a><br />
...or install the gem version 0.1.0 "gem install viewpoint"<br />
<br />
<br />
<h1>New SOAP backend</h1>Viewpoint now uses Handsoap as its back-end instead of soap4r. While soap4r does some very nice things for you automatically, it ends up making your code base fairly large and it complicates any customizations that you might want to make. One example is adding custom headers. Soap4r required you to create a subclass to use as a sort of hook. I can do the same thing in Handsoap with a one-liner in the services #on_create_document method.<br />
<br />
<br />
<h1>Models are completely rewritten</h1>The models are completely new and not backward compatible with the old version of Viewpoint. Some of the methods still exist, but don't count on them. I've tried to make this version much more extensible than the last.<br />
<br />
<h1>Configuration loader removed</h1>After much thought I determined it really wasn't the place of a client library to provide a configuration loader for credentials. To that end I removed the need for a .viewpointrc file. If this is something you liked it would be relatively easy to write it into your application. Now authentication configuration information is set via class methods:<br />
<blockquote>Viewpoint::EWS::EWS.endpoint = 'https://mysite.com/ews/exchange.asmx'<br />
Viewpoint::EWS::EWS.set_auth('myuser','mypass')<br />
</blockquote><br />
<h1>Delegate access is supported</h1>One thing that was often asked for, but missing from the previous version was delegate access to mailboxes and calendars. This is now supported via the 'act_as' parameter to the GenericFolder::get_folder method. For example:<br />
<br />
<blockquote>ofolder = Folder.get_folder(:inbox,'otheruser@test.com')</blockquote><br />
If your user has delegate access to the Inbox for otheruser@test.com this operation will retrieve their inbox and allow you to manipulate it as you would with your own Inbox. There is also some support for manipulation of delegate access itself via the methods MailboxUser#add_delegate!, MailboxUser#update_delegate!, and MailboxUser#get_delegate_info.<br />
<br />
<h1>Some Exchange 2010 Stubs</h1><br />
Some of the new features of Exchange 2010 are being stubbed in. I do not have access to an Exchange 2010 server to test them on so I cannot verify if they work or not.<br />
<br />
<h1>Misc other changes</h1>Since it's a complete rewrite there are tons of other changes that you'll notice. I've tried to keep the code comments coming so stay tuned to the API docs for library information. I'll also be posting more examples to my blog.<br />
<br />
<p>So at a glance there you have it. If there are any features you would like to see added or comments please add it to the bottom of this post or add an issue on the <a href="http://bit.ly/viewpoint_ews">Github</a> page. Also, if you're interested in sponsoring an Exchange 2010 account for me please let me know. I would love to try out some of the new advanced query stuff that 2010 has to offer.<br />
</p><br />
<br />
Cheers!<br />
<br />
GITHUB: <a href="http://bit.ly/viewpoint_ews">http://bit.ly/viewpoint_ews</a><br />
RubyGems: <a href='http://rubygems.org/gems/viewpoint'>http://rubygems.org/gems/viewpoint</a><br />
RDOC: <a href='http://rdoc.info/projects/zenchild/Viewpoint'>http://rdoc.info/projects/zenchild/Viewpoint</a>zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com26tag:blogger.com,1999:blog-5127389572085594932.post-24713467492138038382010-06-29T10:28:00.002-05:002010-06-29T10:47:11.658-05:00Ruby and OpenSSL with SSH keysOne of the challenges of dealing with encryption is the management of keys. We have a SSH key, a PGP key (probably multiple), maybe a OpenSSL cert, perhaps another cert somewhere for S/MIME and maybe a ton more for various other purposes. This post is basically an addendum to my last <a href="http://distributed-frostbite.blogspot.com/2010/06/file-encryption-in-ruby-with-openssl.html">File Encryption in Ruby with OpenSSL</a>, but I will step through the code using an SSH key instead. This will minimize the amount of keys you have to manage and it will utilize a key that many people have readily available to them without the need to create yet another encryption key.<br />
<br />
<h1>SSH Keys</h1><br />
On the chance that you do not have an ssh key (you really should you know) or you are using DSA keys you will need to create an RSA key with ssh-keygen.<br />
<br />
<blockquote><span id="ssl_post"><span class="prompt">home$</span> <span class="cmd">ssh-keygen -t rsa -b 2048 -N 'mypass'</span></span></blockquote><br />
<h1>Loading the SSH key in Ruby</h1><br />
Loading the SSH/RSA key is relatively straight forward. Instead of pointing to our generated RSA key from the last posting we will simply point it to the path of our SSH/RSA key and load it with the password we supplied during the ssh-keygen step. I will demonstrate in an irb session. <br />
<br />
<blockquote><span id="ssl_post"><span class="comment"># Require the OpenSSL library</span></span><br />
<span id="ssl_post"><span class="prompt">irb> </span><span class="cmd">require 'openssl'</span></span><br />
<span id="ssl_post"><span class="comment"># Load the SSH key from the default location (Linux/UNIX)</span></span><br />
<span id="ssl_post"><span class="prompt">irb> </span><span class="cmd">key = OpenSSL::PKey::RSA.new(File.read("#{ENV['HOME']}/.ssh/id_rsa"),'mypass')</span></span></blockquote><br />
The generated public SSH/RSA key is not stored in PEM format so you cannot consume it with OpenSSL, but you can generate it from the private key and store it alongside the SSH formatted one.<br />
<br />
<blockquote><span id="ssl_post"><span class="comment"># Write the PEM encoded public key alongside the SSH public key</span></span><br />
<span id="ssl_post"><span class="prompt">irb> </span><span class="cmd">File.open("#{ENV['HOME']}/.ssh/id_rsa.pub.pem") do |f|</span></span><br />
<span id="ssl_post"><span class="prompt">irb> </span><span class="cmd"> f.write(key.public_key.to_pem)</span></span><br />
<span id="ssl_post"><span class="prompt">irb> </span><span class="cmd">end</span></span></blockquote><br />
<br />
So there you go. You can now load your SSH key for encryption/decryption purposes with the OpenSSL library and you won't have to worry about managing keys. All else remains the same and you can do everything that was done in my previous OpenSSL/Ruby <a href="http://distributed-frostbite.blogspot.com/2010/06/file-encryption-in-ruby-with-openssl.html">posting</a>.<br />
<br />
Cheers!zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-72534113827148986242010-06-23T18:51:00.000-05:002010-06-23T18:51:14.305-05:00File Encryption in Ruby with OpenSSL<blockquote><span style="color: yellow; font-size: x-small;">Disclaimer: I am far from an expert on cryptography so there are probably a million things wrong with this. Any constructive criticism is always welcome... but be gentle ;-)</span></blockquote><blockquote><span style="color: #cc0000; font-size: x-small;">REQUIRED: Ruby 1.9 *because of new hash syntax.</span></blockquote><h1>For Starters....</h1>I am often torn when programming between using libraries and following the DIY approach. On one hand you can accomplish a lot in a short time by including libraries that have the functionality you need and just bridging the gaps, but I am often left with the feeling of some loss-of-control and bloat. Obviously some library usage is inevitable, but I do like to take a minimalist approach to including external libraries because the management burden of updating libraries, the effort to make various libraries play together and because moving library-heavy applications between platforms can be... interesting. Most of all I like the learning that takes place when building it yourself. It was for this reason that I decided to see if I could effectively utilize the OpenSSL library that is typically part of a Ruby installation to create my own higher-level encryption/decryption class. Before we dive in I would like to layout the details of the application.<br />
<br />
<h1>Password Management App</h1><br />
I have for years maintained a PGP encrypted file for my account passwords. I had the desire to centralize this and make it more web accessible. In order to do this I wanted assurance that the data was not only encrypted on the wire via SSL, but also at rest. I looked at various Ruby PGP/GPG libraries, but all of the ones I surveyed were wrappers around the GPG binary itself which didn't make it very web host friendly ( I planned on hosting it on <a href="http://heroku.com/">Heroku</a> with a Couchdb backend on <a href="http://cloudant.com/">Cloudant</a>). That was when I decided to look at OpenSSL for file encryption since it is typically part of a Ruby installation and was available on Heroku. I also had the need for public-key encryption so a password store could be shared between two or more people (I share some accounts with my partner).<br />
<br />
<h1>Take One... RSA</h1>I thought I could simply use RSA encryption to meet all my needs and at first it worked quite well. Creating keys was straight forward and encryption/decryption worked well. One caveat is that the string passed to the FileEncryptor#encrypt_string method cannot be larger than the key size + PKCS padding size (11 bytes). So for a 128 byte (1024 bit) key the string should only be 117 bytes (see String#size).<br />
<br />
<script src="http://gist.github.com/450498.js">
</script><br />
<br />
This seemed to work quite well until I remembered that I needed to have the encrypted data be readable by multiple parties. I then had to change my approach and decided to use a symmetric AES key that is then shared between the multiple parties and each person encrypts the key with their RSA public key.<br />
<br />
<h1>Take Two... RSA + AES</h1>In order to accomplish secure use of the AES key we start out the same way as the previous solution by creating a RSA key. It will only be used to secure AES keys that we use to protect certain data stores. So if I have a data store I want to share with my brother I encrypt the data store with an AES key then I encrypt that key with my public RSA key and my brother's public RSA key. Now both he and I can access anything in that store and the AES key is still secure from prying eyes. Here is an overview of the steps taken before I post the code.<br />
<ol><li>Create a RSA key-pair</li>
<li> Create an AES key to encrypt the data store</li>
<li>Encrypt the AES key with your RSA public key</li>
<li>To give access to the data store encrypt the AES key with the person's public RSA key send them back the cipher-text. </li>
</ol><br />
And here is the class I wrote to make this work:<br />
<br />
<script src="http://gist.github.com/450500.js">
</script><br />
<br />
Below is a demonstration of the use of this class to accomplish the needs I had for my password protector application. I am aware that this class needs some refactoring and it's a bit annoying to have to pass the AES key file to the methods, but logically it is working the way I had hoped.<br />
<br />
<br />
<blockquote style="color: orange; font-family: "Courier New",Courier,monospace;"><br />
fe = Encryptor.new('mysecret')<br />
<br />
aesfile = 'aeskey.sec'<br />
<br />
fe.gen_aes_key(aesfile)<br />
<br />
etxt = fe.aes_encrypt('this is a test', aesfile)<br />
<br />
txt = fe.aes_decrypt(etxt, aesfile)<br />
<br />
pub_key = < Assume I got someone's public RSA Key somehow ><br />
<br />
fe.give_aes_key(aesfile, pub_key)</blockquote><br />
Like I mentioned, this code needs to be cleaned up a bit, but it gives me all of the functionality I need to build my application and it doesn't require any external libraries except OpenSSL and YAML which are typically standard in any Ruby installation.<br />
<br />
Hopefully someone finds this post useful and if you have any additions, corrections, criticisms please post them below. Feedback is always welcome.<br />
<br />
Cheers!zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-90865210621853228882010-04-07T09:57:00.003-05:002010-04-07T10:12:25.488-05:00Using Ruby with Zenoss - Part 2This is the second installment of <i>Using Ruby with Zenoss</i>. This posting will mainly focus on using the library. If you have not read <a href="http://distributed-frostbite.blogspot.com/2010/04/using-ruby-with-zenoss-part-1.html">Part 1</a>, I would strongly recommend going there first in order to make sure your environment is set up correctly.<br />
<br />
In creating the Zenoss library for Ruby I have tried to keep the interface to the programmer fairly similar to the Python API. It is somewhat simplified because the depth of modules and classes don't map one-for-one to a REST client world. There is still much to be in its implementation, but here are a few examples of what you can do with the library today.<br />
<br />
<br />
<br />
<h3>Requiring the gem</h3><i style="color: #ffd966;">!!! You need to have at least version 0.0.4 of the gem installed. !!!</i><br />
<br />
Make sure you add this to any of the following examples:<br />
<blockquote>require 'rubygems' # if you're using gems<br />
require 'zenoss'</blockquote><br />
<h3>Getting Started</h3>You need to tell zenoss_client where to point and how to authenticate. To do that use the following code:<br />
<br />
<blockquote># Set the base uri that we talk to Zenoss with. Your host will<br />
# be unique but the port will probably be 8080 unless you proxy<br />
# it through 80.<br />
Zenoss.uri 'https://<zenhost>:<port>/zport/dmd/'<br />
<br />
# Add the appropriate credentials<br />
Zenoss.set_auth('user','pass')<br />
</port></zenhost></blockquote><br />
<h3>Getting a list of devices</h3>Now that we're set up we can get down to it. One of the primary things that I find myself doing is managing devices through the REST interface. You need a starting point so let's get the base Device class ( /zport/dmd/Devices ):<br />
<br />
<blockquote>devices = Zenoss.devices</blockquote><br />
You can think of the 'Zenoss' object as a slimmed down equivalent of 'dmd' in the zendmd Python interface.<br />
<br />
If you want to start at a DeviceClass deeper in the tree you can do so by passing the path to DeviceClass:<br />
<br />
<blockquote>linux = Zenoss::Model::DeviceClass.new('/Devices/Server/Linux/')</blockquote><br />
Once you have your DeviceClass you can list the devices beneath it like so:<br />
<br />
<blockquote>subdevs = linux.get_sub_devices</blockquote><br />
<h3>Device Info</h3>Using the Device Array from the last step, we'll take the first device and get some information from it.<br />
<br />
<blockquote>mydev = subdevs.first<br />
<br />
# Get the status id<br />
mydev.get_status<br />
<br />
# Get the icon associated with this status<br />
mydev.get_status_img_src(mydev.get_status)<br />
<br />
# Get uptime<br />
mydev.sys_uptime<br />
<br />
# Fetch some RRD Values<br />
dps = mydev.get_rrd_data_points<br />
dsnames = []<br />
dsnames << dps[1].name<br />
dsnames << dps[2].name<br />
mydev.get_rrd_values(dsnames)<br />
# => {"laLoadInt1_laLoadInt1"=>"252.27000000000001", "laLoadInt15_laLoadInt15"=>"255.86000000000001"}</blockquote><br />
<h3>Systems</h3>The library has basic support for Systems now. It's mainly just the ability to create and delete subsystems. More support is forthcoming.<br />
<br />
<blockquote># Fetch the base '/Systems' System<br />
systems = Zenoss.systems<br />
<br />
# Create a new subsystem<br />
ltst = systems.add_subsystem('linuxtst')<br />
<br />
# delete the newly created System<br />
ltst.delete!</blockquote><br />
<h3>That's it, go play</h3>That's a quick introduction to the Zenoss Ruby library. I'm adding new functionality all the time so check for updates often. The code is up on github at <a href="http://github.com/zenchild/zenoss_client">http://github.com/zenchild/zenoss_client</a> so if you want to fork it and help out with development you're welcome to do so. If you're not interested in developing it but would like to see a feature added please comment below or open up a ticket on github and I'll get to it as time allows. I hope you find the library useful.<br />
<br />
<b>Addendum:</b> The RDocs are available at <a href="http://rdoc.info/projects/zenchild/zenoss_client">http://rdoc.info/projects/zenchild/zenoss_client</a><br />
<br />
Cheers,<br />
<br />
Danzenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com0tag:blogger.com,1999:blog-5127389572085594932.post-26185098661976523792010-04-01T08:54:00.002-05:002010-04-05T11:11:31.344-05:00Using Ruby with Zenoss - Part 1I have been using <a href="http://www.zenoss.com/">Zenoss</a> now for over a year and for the most part have been quite happy with it. It's quite customizable and you can find a way to pretty much monitor anything if you put some thought into it. However, my one point of contention has been with the REST interface. Most things work as you would expect, but somethings blow up and don't give you a very good reason except for a nice Zope stack-trace. Prior to using Zenoss, I had very little experience with Zope so some of my issues were simply just lack of knowledge of how REST methods were called from within it. I wrongly thought that there was a translation layer that sat between the web user and the back-end to marshal and unmarshal datatypes. This does not seem to be what is going on. So if I can sum up all of the issues that I struggled with it's this:<br />
<ul><li> If the Python method you're calling on the back-end is expecting something other than a string you're probably going to have issues.</li>
</ul>So, coupled with my poor knowledge of Zope and my frustration on how to call REST methods in a consistent way, I decided to create a library for Zenoss in Ruby. My goal was to create that middle layer to correctly marshal and unmarshal data-types. <br />
<blockquote><i><span style="font-size: x-small;">I chose Ruby because I find it a fun language to program in and well, I guess that pretty much sums it up ;-)</span></i></blockquote> In order for the library to work there is one thing that you need to do on the Zenoss/Zope side. To marshal data-types into Python you most certainly need to do it in Python so we have to add a custom script to Zope.<br />
<ol><li>Go to the Zope Management page:</li>
<ul><li>http://zenoss:8080/zport/dmd/manage</li>
</ul><li> Select "Script (Python)" from the upper-right drop-down</li>
<ul><li>ID = callZenossMethod</li>
<ul><li>"Add and Edit"</li>
</ul><li>Title = "Work around for unsupported Zenoss methods"</li>
<li>Parameter List = methodName</li>
<li>Clear out the code contents from the text box and cut-and-paste the code found here:</li>
<ul><li><a href="http://gist.github.com/343627">http://gist.github.com/343627</a></li>
</ul><li>"Save Changes" </li>
</ul></ol>Once the custom Python is in place simply install the ruby gem:<br />
<ul><li>gem install -r zenoss_client</li>
</ul>That's it, you should be ready to roll. Check back here soon for the second part of this post for example usage of the zenoss_client library.<br />
<br />
<hr /><br />
<b>addendum:</b> Link to zenoss_client source code: <a href="http://github.com/zenchild/zenoss_client">zenoss_client</a>zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-23794766199368316352010-02-02T09:23:00.004-06:002010-02-15T08:36:31.036-06:00Closing Javascript Alerts in Selenium Tests<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_0K-DpiDHGXQ/S2hAMoVI3rI/AAAAAAAABm8/qfUoJ16B5PE/s1600-h/alert.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/_0K-DpiDHGXQ/S2hAMoVI3rI/AAAAAAAABm8/qfUoJ16B5PE/s320/alert.png" /></a></div>I have been plagued some time now with a problem in my Selenium testing, the dreaded modal Javascript alert generated from the "onload" event (See the <a href="http://wiki.openqa.org/display/SRC/Selenium+RC+FAQ#SeleniumRCFAQ-I%27mgettingapopupduringmytestandmytestfreezes.WhatcanIdoaboutit%3F">Selenium FAQ</a> for more info). OK, maybe dreaded is a bit strong of a word, but it has been quite frustrating in trying to automate vendor provided code that we cannot change. Finally there is a fix.<br />
<br />
Jason Huggins, the creator of Selenium, <a href="http://www.infoq.com/presentations/huggins-hacking-selenium">presented</a> at JSConf 2009 and demonstrated a way around Javascript alerts that Selenium cannot handle. After speaking with Jason, he provided me with the original code snippet from Aaron Boodman and I have created a Firefox extension for general use that can be <a href="http://github.com/zenchild/FirefoxAlertCloser">downloaded</a> from my Github site.<br />
<br />
The magic happens in a function called alertClose. If all you need to do is close an alert it should work unmodified for you. If you need to do something a little more exotic you may need to edit the <i><b>subject.location</b></i> which specifies what types of windows it closes. By default it points to <i>chrome://global/content/commonDialog.xul</i>, which is the chrome type for alert boxes. There is a <a href="http://kb.mozillazine.org/Dev_:_Firefox_Chrome_URLs">Mozillazine article</a> that has a listing of the various types of chrome windows if you need to customize.<br />
<br />
<script src="http://gist.github.com/292732.js"></script><br />
<br />
So there you have it. A very simple way to get around Javascript alerts. Hopefully this solution is only temporary and the new <a href="http://google-opensource.blogspot.com/2009/05/introducing-webdriver.html">WebDriver</a> code being integrated into Selenium 2 will work around it in a more elegant way.zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com1tag:blogger.com,1999:blog-5127389572085594932.post-87872438558361826152009-12-10T20:15:00.002-06:002009-12-10T20:18:42.764-06:00Converting from Soap4r to HandsoapA neat little project was mentioned to me the other day in a conversation on GitHub with user <a href="http://github.com/jrun">JRun</a>. It's called <a href="http://wiki.github.com/unwire/handsoap">Handsoap</a> and it has some very interesting features that look to make programming SOAP clients a bit easier. I've had a couple days to look at it and decided to try and port some code to it. My first impressions have been fairly positive. It gives you tremendous power on how you handle your SOAP requests and responses, but I find it just as cumbersome as Soap4r in it's handling of complex types. I think Soap4r might gain out in this category just by the shear amount of code that gets generated for you. That said, Handsoap is fast, simple and I will probably use it in future projects that require SOAP.<br />
<br />
One thing I did find much easier to deal with is SOAP headers. In Soap4r I had to create an entire class just to add an element to the SOAP header. This was required for my <a href="http://github.com/zenchild/Viewpoint">Viewpoint</a> project to add the <a href="http://msdn.microsoft.com/en-us/library/bb891876.aspx">RequestServerVersion</a> element to the header. With Handsoap all I had to do was add the following to the 'on_create_document' hook:<br />
<br />
<code><br />
header = doc.find('Header')<br />
header.add('t:RequestServerVersion') {|rsv|<br />
rsv.set_attr('Version','Exchange2007_SP1')<br />
}<br />
</code><br />
<br />
If you have programmed with Soap4r before I would encourage you to give Handsoap a try.zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com0tag:blogger.com,1999:blog-5127389572085594932.post-58091784327428741942009-12-10T19:52:00.000-06:002009-12-10T19:52:12.377-06:00Convert your Exchange Calendar to iCalendar with RubyThis example is one that is already in the README, but I thought I'd post it here anyway. The reasons for converting an Exchange calendar to ical may be many so I won't surmise why you want to do this. I for one use it to export out to my <a href="http://www.kolumbus.fi/%7Ew408237/orage/">Orage</a> calendar.<br />
<br />
So without further ado ...<br />
<br />
<script src="http://gist.github.com/253917.js"></script>zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com2tag:blogger.com,1999:blog-5127389572085594932.post-52739752770290817622009-12-08T09:15:00.000-06:002009-12-08T09:16:35.658-06:00Viewpoint Examples ForthcomingI recently started writing a library in Ruby that utilizes the Microsoft Exchange Web Service (EWS) to perform some rudimentary tasks. I was asked by a couple people to provide more examples on how to use the library. I will be doing so in upcomming blogs. In the meantime you can look at the library for yourself here:<br />
<a href="http://www.blogger.com/goog_1260285381904"><br />
</a><br />
<a href="http://github.com/zenchild/Viewpoint">http://github.com/zenchild/Viewpoint</a><br />
<br />
It is also available via a gem:<br />
<br />
gem install viewpoint<br />
<br />
There is a bug tracker on Github. If you have any issues please open a ticket.<br />
<br />
Have fun and let me know how you are using it.zenchildhttp://www.blogger.com/profile/09769955793985743717noreply@blogger.com0