20061010 Tuesday October 10, 2006

Salute to our Troops

Salute to our Troops
Originally uploaded by Berin Loritsch.
I've never been in the armed forces, but living in the DC area I am surrounded by military men. I have the utmost respect for those who are willing to do all they can for our freedom. I'm privileged to live in this country, particularly for my freedom of worship.

I'm not one to glorify war, or to romanticize the darker periods of history. Still, it takes a certain quality of person to endure the hell known as war. It's to these brave men and women that I solute.

I know there are a lot of folks who disapprove of the US actions abroad, particularly in the middle east. I'm not one to argue for or against those actions. I'm just a voice saying, "Remember the fallen, and what they died for". They didn't die for oil, or monetary gains. They aren't mercenaries. They died for freedom, for the honor of their country. (2006-10-10 09:41:57.0) Permalink Trackback Comments [0]

20060830 Wednesday August 30, 2006

I know I haven't posted anything new lately....

Much has happened and I am wildly busy. I have a new office in Washington D.C. for a short term contract (2-3 months). I have bought and devoured some Ansel Adams technique books. Man, the Zone system makes a whole lot more sense now. Not to mention I really want to buy a view camera too. I have many comments to post later when I have a bit more time.

(2006-08-30 18:06:48.0) Permalink Trackback

20060724 Monday July 24, 2006

New Old Camera

New Old Camera
Originally uploaded by Berin Loritsch.
I bought a Super Ricohflex, which is an older Twin Lens Reflex (TLR) camera. The top lens is for focusing and the bottom lens is for picture taking. I was expecting a more hefty camera, but this one is fairly light. In fact I was very surprised at its size. As you can see by the picture the TLR is shorter than a Wacom tablet pen.

The Super Ricohflex has a limited set of applications it can be used for, and it likes doing things a little differently. The lens is a wide angle 80mm lens, and to be different they marked it as an 8cm lens. It has seven apertures marked in full stops ranging from f/3.5 to f/16. The most limiting part of the camera is the range of shutter times. It has six times marked: 1/200, 1/100, 1/50, 1/25, 1/10, and B (bulb). I have to have the right lighting conditions if I want to use the smaller apertures, which is not something that will take place in daylight. Since I like to use Provia slide film (a daylight balanced film), using it indoors will likely have a strong yellow or orange cast to it.

I'll report on picture quality when I get the pictures back tonight. It is a medium format camera, and uses 120 format film (6cm wide, 120mm long). It will fit 12 square pictures on the film.

While the controls do require some getting used to, particularly for someone spoiled by SLR cameras with all sorts of automatic gadgetry, it's really not that difficult to use. To focus, you pop up a hood on the top and look down. Because the picture is reflected up to you, your left to right directions on the viewfinder are reversed. That said, the hood also has a magnifying glass to assist with critical focus. Once you are done with the focusing, you can look down on the side of the upper lens to see how much depth of field you have. All in all, you can't complain about something as simple as this camera. (2006-07-24 07:22:42.0) Permalink Trackback Comments [2]

20060709 Sunday July 09, 2006

I'm back!

If you want to vacation in style, take a Disney cruise. It was awesome. Our meal servers were very attentive (even going so far as to remove chives from some ribs for my son), and there is nothing like not having to touch your luggage as it moves from resort to cruise to resort to the plane. I‘ve taken about 15 rolls of film which will need to wait until the 15th to get developed. This has been really fun.

(2006-07-09 19:34:49.0) Permalink Trackback

20060629 Thursday June 29, 2006

Going on Vacation

I‘ll be back in a bit over a week, but we are finally going on our long awaited 10th anniversary cruise. We have been looking forward to this for a long time. So don‘t expect any updates for a bit. When I get back there will be plenty of cool pics to share.

(2006-06-29 10:36:19.0) Permalink Trackback

20060621 Wednesday June 21, 2006

Taste and See...

Taste and See...
Originally uploaded by Berin Loritsch.
Stenciling gone right. I shot Provia 100 in our kitchen, metering off of the new design work in our kitchen. I must say that I am impressed with the dynamic range available in Provia. The colors are very natural, and it almost has a National Geographic feel to it. (2006-06-21 23:03:06.0) Permalink Trackback

20060613 Tuesday June 13, 2006

Big Fat Loser

Originally uploaded by Berin Loritsch.
I'm fed up. After seeing myself in some pictures like this, I'm going to lose weight. I'm starting with the brain hack process of drinking nothing but water for two hours each day. In the space of that two hours will be one glass with a teaspoon of sugar. So far I need to bump it up another notch. No more snacks--no matter how stressful the day is. (2006-06-13 09:04:33.0) Permalink Trackback Comments [1]

20060506 Saturday May 06, 2006

Red Sunset

Red Sunset
Originally uploaded by Berin Loritsch.
I finally figured out the scanner setting to get quality scans from the images. This picture looks like one of the ones Bryan Peterson uses in his book "Understanding Exposure". I have to say the grain quality of slides is far superior to anything in negatives. Problem is that both the film and the processing is at least twice as expensive.

This particular picture was taken in my neighborhood, and the trees were silluetted against the beautiful sky. The slide is more dramatic than real life, and I really like it. (2006-05-06 21:06:26.0) Permalink Trackback Comments [1]

20060505 Friday May 05, 2006

First Set of Slides

Originally uploaded by Berin Loritsch.
It's funny, but slides have their own set of challenges. I've gotten used to getting decent results with negatives, despite the orange tint. However the first set of slides came out too dark. I don't even think it is the original. When I hold the slide up to the light I have beautiful, rich color. When I scan it in it is very dark.

I'm playing around with some settings, but I do need to up the exposure by default with these. (2006-05-05 23:40:48.0) Permalink Trackback

20060428 Friday April 28, 2006

Role Based Authorization in Ruby on Rails

I'm rereleasing all the articles on D-Haven so that when I upgrade the site they have a home.

Ruby on Rails is a great web framework, and it does simplify many aspects of writing a dynamic web application. While rails does have a login generator, it does not provide support for role based authorization. This article details how to extend the login to include role based authorization.

Role based authorization provides protection in the sense of enabling users who are trusted at different levels access to what they need at their trust level. For example, you may have an article submission system with all users able to add comments, some users able to submit and edit articles, and administrators able to delete articles. This level of access control enables the system to protect itself from accidental abuse.

Step 1: Enable logins

You will need to install the "login" generator for rails. Just follow the instructions on the LoginGenerator page. At that point, you just need to generate the login with a command similar to this:

$ script/generate login User

Next, set up your database with a table for the logins. The table name needs to be "users", with the set of columns listed below.

  1. id, integer, auto-increment, and primary key
  2. login, varchar(20+)
  3. password, char(40)

Note, you can add additional columns if you want to track more information about the user. I like to have a "Name" and an "Email" column in adition to the required columns. That way I can have a better login message than "Welcome bloritsch" and I can also add a process to reset passwords if the user forgot it. That's a subject for another time.

Another additional thing you should do at this time is to change the "salt" value. The login generator allows an application to salt the passwords so that it is not as trivial as finding the SHA1 hash of the password itself. You'll see a line with @@salt = 'change-me'. All you have to do is to replace the contents of the string with your new salt value.

Step 2: User specific authorization

In my article submission scheme, I wanted to make it that the user who submitted an article is the only one who can edit it. Call it an experiment in ownership. I very well may relax that requirement and make it a role based authorization. However, this is the first step in showing how authorization could work.

To enable user specific authorization, you have to associate a user with a controlled item. We will assume you have a model named "Article" which maps to the database table named "Articles". To make the association, you need to add in the reference from Articles to User. You do that by adding the "user_id" column to the "Articles" table. Next, modify your Article model which should be in app/models/Article.rb. Add the line "belongs_to :user" to the top of the class. You should also add to the "validates_presence_of" list the parameter ":user". The articles class will look something like this:

class Article < ActiveRecord::Base
  validates_presence_of :title, :user
  belongs_to :user

Since it is very inconvenient for your user to have to explicitly add themselves to an article we need to alter the controller that manages the articles to automatically associate the logged in user to the article. If you generated the scaffolding already for your articles, this is fairly simple to do. We need to ensure the user is logged in, and then we need to alter the "create" method to make the association.

  1. Add the line before_filter :login_required, :except => [:index, :list, :show] to the top of the class. This will ensure the user is logged in for any action that would alter the data in the articles without forcing them to be logged in to see the articles.
  2. Add the line @article.user = @session[:user] directly after the line @article = Article.new(params[:article]) that was generated from the scaffolding code.

The resulting changes to the Article's Controller should look similar to the following code snippet:

class ArticlesController < ApplicationController
  before_filter :login_required, :except => [:index, :list, :show]
  # ... skip other generated code ...
  def create
    @article = Article.new(params[:article])
    @article.user = @session[:user]
    if @article.save
      flash[:notice] = 'Article was successfully created.'
      redirect_to :action => 'list'
      render :action => 'new'
  # ... skip other generated code ...

So far, we have a user automatically associated with new articles. So far so good, but we aren't really protecting against just anyone altering my article. To do that we need to alter the "edit" method to validate the logged in user is the same as what is already associated with an article. To do that we need to add conditional to the code that is already there. For brevity's sake let's take a look at what it should look like:

  def edit
    @article = Article.find(params[:id])
    if @article.user != @session[:user]
      flash[:notice] = 'You cannot edit an article you didn\'t upload.'
      redirect_to :action => 'show', :id => @article

What we did here was add an if statement that checks to see if the logged in user matches the article's author. If not, the controller flashes the notice "You cannot edit an article you didn't upload." and redirects the user back to showing the article. If you don't like the flash notice approach (it can get lost at the top of a long article) you can adapt the code to your purposes. So far we are performing a certain level of control over the process. What we are trying to do, of course, is to provide a way to protect against spammers or people with nothing better to do than to destroy your hard work.

Step 3: Adding Roles to the Mix

Now that we have authorization happening and some level of user control, we want to have more granular support so that you have to be an "Admin" role to delete an article. Just to make things interesting we will allow the "Admin" role to alter any article just in case it is largely OK, but the original author had some objectionable language in there.

We need to generate a model for "Role" and two tables in the database. We need two tables to provide for a many to many relationship between users and roles. Any role can belong to many users, and any user can have many roles. The database tables should look like this:

Table: Roles
  1. id, int, auto-increment, primary key
  2. role, varchar(20), not null
Table: Roles_Users
  1. user_id, int, primary key
  2. role_id, int, primary key

To allow rails to understand the way they relate to each other in the database, we need to add the directives to associate them. We do this with the line has_and_belongs_to_many and then we cross reference the users with roles and roles with users. It should look something like this:

Model: Role
class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
  #add validation for good measure  
  validates_presence_of :role
  validates_uniqueness_of :role
Model: User
class User < ActiveRecord::Base
  has_and_belongs_to_many :roles
  # ... skip remaining code ...

That's all well and good, but as it stands right now we have to do some fancy checking to see if your user has a particlur role. After all we need to look up the Role object we need, and then see if the array of roles for the User object includes that role. That's alot to ask for the consumer of the system. So lets make it a little easier.

First, let's make it easier to find the Role object that we need. We will assume that we look up a role by the name of the role instead of needing to know what the id is. It makes the code more understandable. To do that we will add a new method to the Role's model. The easiest way to do that is to create a static method overriding the bracket operator like this:

  def self.[] (role)
    find_first(["role = ?", role])

That code allows us to find any role with a very simple call: Role["Admin"]. But wouldn't it be nicer to be a little more Rubyesque in our API and us a symbol for the role? It's really easy to modify the above method to use symbols so that the call looks like Role[:Admin]. Just change the find_first call like this:

    find_first(["role = ?", role.id2name])

Now we just want to find out if our user has a particular role. To do that we need a new method in our User model to check that fact. To keep things easy to use we will call it "is_in_role?" The method should look like this:

  def is_in_role?(role)
    if role.nil?
      return false;
    return roles.include?(Role[role])

That way we guard against an empty role and we can validate if the role exists. Instead of asking the developer to constantly find the proper role himself, we include that logic in the method. That way we can validate if the user is in a particular role like this: @user.is_in_role? (:Admin).

Using the Role Checking in Code

Now that we have effectivley added the role checking code we can start using it. Let's start by extending the user specific checking for editing an article to allow anyone with the role "Admin" to edit the article. This is a relatively simple thing to do. First, we need a role with the "Admin" role defined. Next we need a user with the "Admin" privilege associated. At this point you'll have to add those directly to the database.

Blocking actions in the controller

Now, let's take a second look at the "edit" method in the articles controller. All we need to do is add an additional clause to the if statement to check to see if the role is not in "Admin". The altered if statement should look like this:

    if @article.user != @session[:user] and not @session[:user].is_in_role? (:Admin)
Hiding parts of the view based on role

Let's say that we want to suppress the "Edit" link in the show.rhtml view for the article if the user does not have the "Edit" role. To do that we need to perform our check in the show.rhtml file. If you recall, anyone can view an article without being logged in, so we do need to verify if the user is logged in before we check their role. I did the check like this:

<% if not @user.nil? and @user.is_in_role? (:Edit) %>
  <%= link_to 'Edit', :action => 'edit', :id => @article %> | 
<% end  %>
<%= link_to 'Back', :action => 'list' %>

To enable @user to work, you'll have to add the line @user = session[:user] to the "show" method in the articles generator. It does make it a little easier to handle.

Protecting known URLs

The last thing we need to do is protect against just anyone deleting any article. If they recognize your app as a Rails based app, they will know that the "destroy" method will delete the article. Its best to protect any action before we take it. To do that we need to alter the articles controller again, this time with the "destroy" method. Something that the scaffold generator doesn't do is provide any flash notices whether a delete was successful or not. We are going to fix this oversight at the same time. The method should look like this when it is done:

  def destroy
    if session[:user].is_in_role? (:Admin)
      flash[:notice] = 'Article was successfully deleted.'
      flash[:notice] = 'Only an administrator can delete the article.'
    redirect_to :action => 'list'

What we just did was to validate if the user is in the "Admin" role, and if they were we destroyed the article and flashed the success message. If they were not an Admin, they are notified that they can't delete the article.

We're Done

We have a thing of beauty. We can provide fine grained control, and we have a very flexible role based system we can extend. What we didn't do was user administration or adding a way to manage who gets assigned what roles. That's handled manually in the database. Its up to you to write the rest of that. The good news is that you have the ability to make your administration maintained by only authorized users.

(2006-04-28 16:40:18.0) Permalink Trackback