Friday, November 06, 2015

Kerberos propagation and unusual networking

My Kerberos servers are scattered around the Internet, behind NAT in some cases, connected with VPNs, etc. As such the hostname or IP that one server might use to connect to another is often different from the actual hostname or default IP of the other server.

For most services this isn't a particular challenge, but Kerberos replication with kprop and kpropd has often been difficult to get working. In moving some of my Kerberos services into Docker I've discovered a few details.

To set the stage, you typically run kprop on your Kerberos master and give it the hostname of a slave to which you are pushing replication.  The slave runs kpropd to accept these connections.

Things I've found:

The hostname you give to kprop must be the actual hostname on the slave. In some ways Docker makes this easier as you can put kpropd in its own container and set the necessary hostname. If the hostnames do not match then kprop will fail with:

kprop: Server rejected authentication (during sendauth exchange) while authenticating to server
Generic remote error: Key table entry not found

The IP address that kprop connects to must be an IP address on the slave. NAT or Docker's default networking, where you expose particular ports with the -p flag and Docker does NAT and PAT, is incompatible with kprop. I got around this by using a VPN and Docker's --net=host style of networking. If the slave doesn't know about the IP address that kprop used then kprop will fail with:

kprop: Incorrect net address signalled from server
Error text from server: while decoding database size

Wednesday, November 07, 2012

Raspberry Pi, Raspian Debian Wheezy, Boot Single User Mode

In short, eject the SD card from your Pi, mount it somewhere, and add "single" to the end of cmdline.txt.  I was able to stick the card in my Mac and edit the file.  Eject the card from that computer, stick it back in the Pi and boot it up.  As is typical on Linux boxes it will boot to single user mode and prompt you for the root password.

Once you've booted up and fixed whatever needs fixing you can edit /boot/cmdline.txt on a running Pi and remove the "single" keyword.

Friday, September 07, 2012

Reporting Input Errors from a Rails Model

There are several places outside of the standard validations where you might process user input in a Rails model and want to inform the user that they supplied bad data.  It is not immediately obvious though how you get useful error messages back to the user.  Rails gives your model an instance of ActiveRecord::Errors called errors, which is the standard way to return validation errors.  You have to think of any other user input checking as validation and somehow get error messages into the errors object.

Without further ado, from easiest to hardest:

Standard Validations

With a standard validation Rails handles adding an appropriate error message to errors for you.

class Thing < ActiveRecord::Base
  validates :name, presence: true

Custom Validations

To quote from the Rails guide to custom validation:

"You can also create methods that verify the state of your models and add messages to the errors collection when they are invalid."

class Thing < ActiveRecord::Base
  validate :custom_validator
  def custom_validator
    errors[:name] << 'This is a custom validation error on name'

Before Validation Callback

Rails provides callbacks at a number of stages of model processing.

To quote from the Rails guide regarding halting execution in a callback:

"If any before callback method returns exactly false or raises an exception, the execution chain gets halted and a ROLLBACK is issued; after callbacks can only accomplish that by raising an exception."

"Raising an arbitrary exception may break code that expects save and its friends not to fail like that. The ActiveRecord::Rollback exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised."

It doesn't mention that before_validate callbacks have another option.

Specialized validation should normally go in a custom validator, but if for some reason you have to perform a check in a callback then any time you are processing user input you should do that in a before_validate callback.  Using before_validate allows you to use the standard errors object, which behaves just like it does in a custom validator.

class Thing < ActiveRecord::Base
  before_validation :bv
  def bv
    errors[:name] << 'This is a before validation error on name'

Virtual Attribute

You can define virtual attributes in a model.  As shown in the RailsCast you can use custom validation for simple cases.  But some virtual attributes may be doing complex processing that causes you to discover errors in the user input inside the virtual attribute method.  Assignment methods are called before validation.  They're even called before the before_initialization callback for any virtual attributes you pass via new/create.

Apparently this is too early in the process to use the standard errors object, anything added to errors is ignored.  But since these methods execute before validation we can just save up any errors and insert them into the standard errors object during the validation stage.

class Thing < ActiveRecord::Base
  def virtual=(virtual_value)
    @virtual_errors = {name: ['Virtual is invalid']}
  before_validation :bv
  def bv
    @virtual_errors.each do |k,v|
      v.each { |e| errors[k] << e }

Thursday, June 14, 2012

Rails, simple_form, Twitter Bootstrap, and append

I wanted to put a little delete button at the end of a form field.  We start with the standard simple_form syntax for a form field.

  <%= f.input :name %>

The generated HTML has the form elements inside a set of nested divs which have the classes necessary for Bootstrap styling.

The result looks like:

If we want our delete button to appear on the same line as the form field we need to get it inside those divs.  The Wrapping Rails Form Helpers section of the simple_form documentation explains that you can pass a block to the input method, and some of the developers mentioned in ticket comments on Github that this can be used to add content near the form field.  There seems to be some discussion about improving the syntax so that you don't have to list the name of the model attribute twice, but for now that is necessary.

  <%= f.input :name do %>
    <%= f.input_field :name %>
    <%= button_tag content_tag(:i, nil, class: 'icon-remove'), type: 'button', class: 'btn btn-danger' %>
  <% end %>

The result looks like:

Looking good.  But a review of the Bootstrap documentation for forms turns up their "Append with button" example.  For that effect we need an extra div with the "input-append" class.  It isn't documented, but poking around in the simple_form code you'll find the :append wrapper which looks to do what we need.  Note that the lack of space between the input_field and the button_tag is important, otherwise you get a bit of whitespace in the resulting page.

  <%= f.input :name, :wrapper => :append do %>
    <%= f.input_field :name %><%= button_tag content_tag(:i, nil, class: 'icon-remove'), type: 'button', class: 'btn btn-danger' %>
  <% end %>

The result looks like:

Thursday, April 19, 2012

Rails.root is the new Rails.configuration.root_path

In older versions of Rails the Rails.configuration.root_path method would give you the base directory of your application in the filesystem.  In Rails 3 this is now Rails.root.

Friday, March 23, 2012

Rails, as_json, undefined method `serializable_hash'

as_json was failing in one of my Rails models with:

NoMethodError: undefined method `serializable_hash' for ["id", 3]:Array

Eventually figured out that the problem was that I had specified a non-existent association to :include in as_json:

  def as_json(options={})
    super(:include => [:non_existent_association])

Thursday, February 02, 2012

Versioning RESTful APIs

There seems to be general (but definitely not complete) consensus among REST experts that the proper way to version a REST API is via custom MIME/media types.  You can Google this for yourself to find the discussions on the rest-discuss mailing list, Stack Overflow, various blogs, etc.

There was one subtlety to the discussion that I found interesting and I spent some time researching.  Most folks propose media types like:


However a few folks, based on examples in the section of the HTTP spec for the Accept header, suggest a format like:

"application/vnd.mycompany.myapp+xml; level=2"

That's often countered with the argument that an "accept-extension" like "level" is optional (with the implication that it can be ignored if present, which seems like an unfounded assumption), or that it should only be used to indicate minor versions.

However my reading of the examples in the HTTP spec and related historical documents leads me to believe that using "level" to indicate major versions was exactly the intended purpose. All usage of the "level" extension historically seems to have been in relation to the “text/html” MIME type, and specifically to indicate major versions of the HTML spec (HTML 2, HTML 3, etc.) This page ( dated 1995 clearly shows usage of a "text/html; level=3" media type to indicate to HTML 2 only clients that they won’t understand the markup and should not attempt to do so.

That said, this is largely an academic exercise. In the absence of specific definition it seems like media types must be treated as opaque strings, so "application/vnd.mycompany.myapp-v2+xml" and "application/vnd.mycompany.myapp+xml; level=2" both serve the same purpose. Since there seems to be consensus that the former is the better format to use I’ll be going that way, I just don’t see any reason that the later format is any less valid. And in fact using the "level" extension for minor versioning seems counter to historical precedent, but (IMHO) acceptable and harmless if used on a custom MIME time.