Archive for the 'Ruby on Rails' Category


Automatically reload Rails plugins 0

I’m writing this blog post in english because it seems to me that many developers still run into this issue. So now it’s up to Google to put them out of their misery…

Automatically reload Rails plugins

I just bought the PDF Plugin Patterns Enhancing Rails 2.1 by Andrew Stewart for getting in touch with best practices for writing a Rails plugin. First of all… this book is awesome. I totally agree to Chris O’Sullivan:

“Bought the [Plugin Patterns] PeepCode PDF…and I gotta say I’m loving it. It’s very well written, and you explain complicated nasty stuff with nice simple examples.”

After reading this book within an hour I started to develop my own plugin acts_as_wizard to make ActiveRecord models suitable for multi-step-forms (aka „Wizards“). I immediately noticed that I had to reload Rails manually every time I changed the plugin code because plugin paths are added to the ActiveSupport::Dependencies.load_once_paths by default. Witold Rugowski suggests adding the plugin to ActiveSupport::Dependencies.explicitly_unloadable_constants and deleting the path from ActiveSupport::Dependencies.load_once_paths or force reloading with ActiveSupport::Dependencies.load_file from a controller.

The wonderful Peepcode book offers a quite easier way…

Reloadable Plugins
If you have done any plugin development at all, you’ll know that changes don’t get picked up until you restart the server. It is tedious.
Happily for us, Rails 2.1 introduced the ability for files in plugins to be reloaded like the rest of the application. To make all plugins reload- able, add the following to your application’s configuration:
You can also switch this on and off per plugin. See the commit log (http://github.com/rails/rails/commit/cc2d6a0b93251fce06bab15c52dbe0a5d5a8342c) for details.

I gave it a try and added config.reload_plugins = true to my environments/development.rb.
It worked – but not for my „acts_as_plugin“. So I wrote an email to the author.

I just bought Plugin Patterns Enhancing Rails 2.1 by Andrew Stewart today.
I’ve a question concerning the following statement on page 95.
In fact it seems that config.reload_plugins = true does not work for acts_as-Plugins, which extend ActiveRecord because ActiveRecord won’t be reloaded anyway (because it’s core part of rails).

Maybe the author has a tip… googling around and trying out did not solve my problem. To be honest… I bought the Peepcode book to avoid this ;-)

After two days I got response from Geoffrey Grosenbach, Mr. Peepcode himself. Cool. And it did the trick. Even cooler.

Here’s another strategy that will definitely work, but requires a bit
of initial configuration.

Summary: Use either unicorn or nginx and Phusion Passenger with my
rstakeout script to automatically restart Passenger every time your
plugin changes.

Unicorn (easy, but untested):

Download my rstakeout.rb script. A copy is here:

http://github.com/EdvardM/rstakeout

Install the unicorn server and start it in your Rails app:

unicorn_rails

Note the PID (“spawned pid=15250″)

In a separate terminal window, run rstakeout.rb, telling it to restart
Unicorn by sending USR2 to unicorn whenever a file in your plugin is
saved:

rstakeout.rb “kill -USR2 15250″ “vendor/plugins/YOUR_PLUGIN/**/*.rb”

Or, a more complicated way (nginx and passenger):

First, install nginx and passenger. Pat Allan has a detailed summary
for running it from inside a Rails app directory here:

http://freelancing-gods.com/posts/script_nginx

If you use his technique, you can start nginx in any Rails directory.

Start nginx (either preconfigured, or with the Passenger Preference
pane if you’re on Mac OS X, or with Pat’s script).

Finally, run this command in your Rails app’s directory to watch the
plugin and restart Passenger:

rstakeout.rb “touch tmp/restart.txt” “vendor/plugins/YOUR_PLUGIN/**/*”

Now, any time you edit a file in your plugin’s directory, Passenger
will be restarted and you’ll be working with the updated code.

Yes, a bit complicated, but I tried something similar here and it did the trick.

Let me know if you try it!

I can confirm that it works. I’m using Passenger and Apache for development on Mac OS X 10.6.2. Great. I just fetched a copy of rstakeout, put it to /usr/local/bin and ran rstakeout.rb “touch tmp/restart.txt” “vendor/plugins/acts_as_wizard/**/*.rb” from my rails application directory. For testing purposes I added a comment to the plugin’s init.rb and rstakeout immediately noticed it.
=> vendor/plugins/acts_as_wizard/init.rb changed, running ‘touch tmp/restart.txt’

By the way… if you install the ruby-growl gem and Growl you’ll get a Fancy-schmancy notification everytime you change something.

Paperclip Watermarking-Processor 0

Trabayo bekommt im Rahmen des X-Mas-Sprints ein paar neue Features, u.a. auch die Möglichkeit zur Integration von Fotos in Service-Profilen, um einer Dienstleistung mehr Ausdruck verleihen zu können. Mittels IPTC-NAA-Annotations werden sinnvolle, maschinenlesbare Metainformationen in die Fotos integriert, sodass diese einen semantischen Kontext bekommen und von Suchmaschinen entsprechend erfasst werden können. Aus verschiedenen Gründen ist es daher erstrebenswert, die Fotos mit einem Wasserzeichen zu versehen, sodass der Bezug zu Trabayo auch optisch direkt hergestellt werden kann. Zu diesem Zwecke habe ich einen Paperclip-Prozessor geschrieben, der wie folgt eingebunden wird.

class Photo < ActiveRecord::Base

  has_attached_file :attachment,
                    :url => '/system/photos/:id/:style/:filename',
                    :styles => {
                      :thumb => ["80x60#", :jpg],
                      :full  => ["800x600>", :jpg]
                    },
                    :watermark_path     => File.join(RAILS_ROOT, 'public', 'images', 'watermark.png'),
                    :watermark_position => 'SouthEast'
                    :watermark_dissolve => 30,
                    :watermark_ratio    => 25,
                    :processors => [:thumbnail, :watermark]
end

Über die optionalen Konfigurationsparameter (:watermark_[path|position|dissolve|ratio]) können Dateipfad zum Wasserzeichen, Position des Wasserzeichens im Foto, Grad der Überblendung und die maximale Größe, die das Wasserzeichen im Gesamtgrößenkontext des Fotos einnehmen darf, bestimmt werden.

# lib/paperclip_proccessors/watermark.rb
module Paperclip
  # Handles watermarking images that are uploaded.
  class Watermark < Processor

    attr_accessor :current_geometry, :whiny, :watermark_path, :watermark_position, :watermark_ratio, :watermark_dissolve

    # Adds a watermark object (+watermark_path+) to the +file+ given.
    # It creates a dissolved (+watermark_dissolve+) layer at (+watermark_position+) and
    # will attempt to transform the watermark to fit a given ratio (+watermark_ratio+).
    # Example: A +watermark_ratio+ of 25 with +watermark_position SouthEast will place the
    # watermark to the left bottom of the given file and, if needed, shrinks it to maximum 25% of either
    # width or height of the file given by keeping its aspect ratio. So it neither crops the watermark
    # nor scales it up. For further positioning details see ImageMagick gravity option.
    # Watermark creation will raise no errors unless +whiny+ is true (which it is, by default).
    def initialize file, options = {}, attachment = nil
      super
      @file                = file
      @current_geometry    = Geometry.from_file @file
      @whiny               = options[:whiny].nil? ? true : options[:whiny]

      @current_format      = File.extname(@file.path)
      @basename            = File.basename(@file.path, @current_format)

      @watermark_path      = options[:watermark_path]     || File.join(RAILS_ROOT, 'public', 'images', 'watermark.png')
      @watermark_position  = options[:watermark_position] || 'SouthEast'
      @watermark_dissolve  = options[:watermark_dissolve] || 30
      @watermark_ratio     = options[:watermark_ratio] || 25
    end

    # Performs the composition of the +file+ with the watermark. Returns the Tempfile that contains the new image.
    def make
      src = @file
      dst = Tempfile.new(@basename)
      dst.binmode

      command = <<-end_command
        #{transformation_command}
        "#{File.expand_path(src.path)}[0]"
        "#{File.expand_path(dst.path)}"
      end_command

      begin
        success = Paperclip.run('composite', command.gsub(/\s+/, ' '))
      rescue PaperclipCommandLineError
        raise PaperclipError, "There was an error processing the watermark for #{@basename}" if @whiny
      end

      dst
    end

    # Returns the command ImageMagick's +composite+ needs to add the watermark to the image.
    def transformation_command      

      watermark_max_width  = (@current_geometry.width.to_i * (@watermark_ratio.to_f / 100)).to_i
      watermark_max_height = (@current_geometry.height.to_i * (@watermark_ratio.to_f / 100)).to_i

      trans = " -dissolve #{@watermark_dissolve} -gravity #{@watermark_position} \\( '#{@watermark_path}' -resize #{watermark_max_width}x#{watermark_max_height} \\) "
    end
  end
end

Authlogic HowTo + Source-Code 4

Wir alle kennen das übliche Anmelde-Prozedere bei praktisch allen Web-Applikationen, die mit individuellen Benutzerdaten arbeiten. Am Anfang steht die Registrierung, bei der wir mindestens einen (hoffentlich noch verfügbaren) Benutzernamen, ein (möglichst sicheres) Passwort und unsere E-Mail-Adresse angeben müssen. An letztere wird üblicherweise im Anschluß ein Bestätigungslink versendet, um sicherzustellen, dass wir auch Inhaber des Postfaches sind. Nach erfolgreicher Bestätigung steht dann einem ersten Login-Versuch nichts mehr im Wege: anhand der von uns vergebenen Kombination aus Benutzername und Passwort können wir uns jederzeit an der Web-Applikation anmelden und auf persönliche Daten und individuelle Einstellungen zugreifen.
Das, was für den Benutzer der Web-Applikation mittlerweile obligatorisch ist, stellt den Entwickler derselben jedoch vor eine Vielzahl von zu bewältigenden Aufgaben und bringt nicht zuletzt auch eine Menge Pflichten mit sich. Denn immerhin obliegt es der Sorgfalt des Entwicklers, dass vertrauliche Daten vor unbefugtem Zugriff Dritter geschützt sind und im Falle einer Kompromittierung der Web-Applikation der Schaden so gering wie möglich gehalten wird.

RESTful Authentication – berechtigter De-facto-Standard?

Das RESTful Authentication Plugin des Ruby on Rails Core Members Rick Olson galt lange Zeit als etablierter De-facto-Standard zur Implementierung eines Authentifizierungs-Features. RESTful Authentication besteht dabei im wesentlichen aus einem Generator nebst Templates und einem Authentifizierungsmodul. Die vermeintlichen Vorteile dieses Ansatzes sind nicht nur die Erzeugung aller relevanten Komponenten innerhalb einer Rails-Applikation, sondern auch die Integration des Authentifizierungssystems in zentrale Bestandteile wie Routing, Helper & Co. Diese vermeintlichen Vorteile kehren sich jedoch schnell zu erheblichen Nachteilen um, sofern man selbst Anpassungen an der Authentifizierungsroutine vornehmen möchte. Spätestens dann ist man mit den über die Applikation verteilten Code-Fragmenten konfrontiert, sodass unterm Strich fast schon mehr Aufwand entsteht, als eine vollständige Implementierung „from scratch“ in Anspruch nähme.

Authlogic und der Grund, warum wir Rails lieben

Einer der vielen Gründe, die für die Entwicklung mit Ruby on Rails sprechen, ist die vorgegebene, klare (MVC-)Struktur einer typischen Applikation und die Integration bewährter Entwicklungsparadigmen. Besonders das „Convention over Configuration“-Paradigma schafft eine sinnvolle Grundlage, sodass sich der Entwickler auf das Wesentliche der Applikation konzentrieren kann. Authlogic folgt diesen Grundgedanken des „RailsWay“ und macht sie zu seinen Erfolgsprinzipien.

„A code example can replace a thousand words“ (Ben Johnson)

Ausgehend von einem frisch erzeugten Applikationsgrundgerüst muß zunächst das Plugin installiert werden:

$ ruby script/plugin install git://github.com/binarylogic/authlogic.git

Für diesen Artikel verwende ich der Einfachheit halber die Installation des Plugins. Alternativ kann aber natürlich auch das RubyGem verwendet werden:

$ gem sources -a http://gems.github.com
$ sudo gem install binarylogic-authlogic

Bei der Verwendung des RubyGems empfiehlt es sich zudem, in der config/environment.rb eine entsprechende Abhängigkeit zu definieren:

config.gem ‘binarylogic-authlogic’

Im Anschluß können wir bereits direkt ein Model erzeugen, welches von der Klasse Authlogic::Session::Base abgeleitet wird.

$ script/generate session user_session

Das besondere an diesem Model ist, dass es sich um das gesamte Session-Management kümmert und wie ein ActiveRecord-Model verwendet werden kann. Uns hindert also nichts daran, einen REST-konformen Controller (Listing 1) zu erzeugen, wie wir es auch für ein ActiveRecord-Model tun würden.

$ script/generate controller user_sessions

Listing 1

class UserSessionsController < ApplicationController

  before_filter :require_no_user, :only => [:new, :create]
  before_filter :require_user,    :only => :destroy

  def new
    @user_session = UserSession.new
  end

  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = 'Hi, you are logged in!'
      redirect_back_or_default account_url
    else
      render :new
    end
  end

  def destroy
    current_user_session.destroy
    flash[:notice] = 'Goodbye, you are logged out!'
    redirect_back_or_default new_user_session_url
  end
end

Das Routing für diesen Controller wird ebenfalls, wie gewohnt, in der config/routes.rb definiert.

map.resources :user_sessions

Die Views sind äußerlich nicht von denen zu unterscheiden, die via Controller mit ActiveRecord-Objekten interagieren (Listing 2). Im Gegensatz zu RESTful Authentication stehen daher auch die gewohnten Methoden zur Darstellung von etwaigen Fehlern zur Verfügung.

Listing 2

# /app/views/user_sessions/new.html.erb

Login

< % form_for @user_session do |f| %> < %= f.error_messages %> < %= f.label :email %> < %= f.text_field :email %> < %= f.error_message_on :email %> < %= f.label :password %> < %= f.password_field :password %> < %= f.error_message_on :password %>
< %= f.submit 'Login!' %> < %= f.check_box :remember_me %> < %= f.label :remember_me, 'Remember me?', :class => 'check_box' %>
< % end %>

Nützliche (und für dieses Beispiel auch notwendige) Methoden, z.B. das sich selbst erklärende redirect_back_of_default, werden zentral im ApplicationController definiert (Listing 3).

Listing 3

class ApplicationController < ActionController::Base

  protect_from_forgery

  helper :all
  helper_method :logged_in?, :current_user_session, :current_user
  filter_parameter_logging :password, :password_confirmation

protected    

  def store_location
    session[:return_to] = request.request_uri
  end

  def redirect_back_or_default(default)
    redirect_to(session[:return_to] || default)
    session[:return_to] = nil
  end 

  def current_user
    @current_user ||= current_user_session and current_user_session.user
  end 

  def current_user_session
    @current_user_session ||= UserSession.find
  end 

  def logged_in?
    not current_user.nil?
  end 

  def require_user
    unless logged_in?
      store_location
      flash[:notice] = 'Please login in to access this page!'
      redirect_to new_user_session_url
      return false
    end
  end

  def require_no_user
    if logged_in?
      store_location
      flash[:notice] = 'Please logout to access this page!'
      redirect_to account_url
      return false
    end
  end

end

Damit ein Benutzer nach einem erfolgreichen Login auf seine persönliche Seite weitergeleitet wird, definieren wir noch einen AccountsController (Listing 4) und eine Route für die dazugehörige, singuläre Resource in der config/routes.rb:

$ script/generate controller accounts

# config/routes.rb
map.resource :account, :only => :show

Listing 4

class AccountsController < ApplicationController

  before_filter :require_user

  def show
    @account = current_user
  end

end

Der AccountsController kann später natürlich noch um weitere Methoden zum Bearbeiten des Profiles erweitert werden. Um jedoch unbefugten Zugriff auf fremde Benutzerdaten zu verhindern, sollte das Basisobjekt ausschließlich mittels der Methode current_user geladen werden. Es sei denn, man implementiert z.B. eine rollenbasierte Autorisierung, bei der ein Zugriff auf alle Benutzerobjekte durch Superuser vorgesehen ist. Wie das funktioniert, schreibe ich in einer der nächsten Ausgaben der RailsWay.

Bitte registrieren Sie sich!

Eine Benutzerauthentifizierung ist jedoch nichts ohne die zugrundeliegenden Benutzer. Und diese sollen sich selbstständig registrieren können. Dazu erzeugen wir zunächst das Model User:

$ script/generate model user

Für eine sinnvolle Minimalkonfiguration, bei der wir die E-Mail-Adresse für den Login verwenden, genügt es, in der dazugehörigen Migration die Attribute email, crypted_password und persistence_token zu definieren (Listing 5). Es sei jedoch bereits jetzt schon erwähnt, dass Authlogic eine Vielzahl von „MagicColumns“ beinhaltet, auf die wir später noch zurückkommen werden.

Listing 5

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :email,               :null => false
      t.string :crypted_password,    :null => false
      t.string :persistence_token,   :null => false
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

Wir führen nun die Migration aus:

$ rake db:migrate

…und teilen dem Model User mit, dass wir es zur Authentifizierung von Benutzerdaten verwenden möchten:

class User < ActiveRecord::Base
  acts_as_authentic
end

Technisch gesehen haben wir bereits jetzt eine vollständige Benutzerauthentifizierung. Beeindruckend einfach, oder? Damit sich Benutzer nun selbstständig registrieren können, müssen wir natürlich auch ein entsprechendes Registrierungsformular bereitstellen. Wir möchten zudem, dass ein Benutzer sich erst dann einloggen kann, wenn er durch Anklicken eines Aktivierungsschlüssels bestätigt hat, dass die zur Registrierung verwendete E-Mail-Adresse auch wirklich ihm gehört. Dieses Bestätigungsprozedere bilden wir in einem endlichen Automaten ab.

Oh, Du Zustandmaschine, Du endlicher Automat!

Beim Schlagwort „Endlicher Automat“ werden bei dem ein oder anderen Leser mit akademischem Hintergrund Erinnerungen an Vorlesung zur Theoretischen Informatik und Automatentheorie wach. Ein endlicher Automat („engl. Finite State Machine“), um den es uns nun geht, beschreibt ein Verhalten bestehend aus Zuständen, Zustandsübergängen und Aktionen. Am Beispiel der Benutzerregistrierung erklärt, gibt es zwei Zustände: bestätigt (confirmed) und unbestätigt (pending). Um nun vom Zustand unbestätigt in den Zustand bestätigt zu wechseln (Zustandsübergang) ist eine Aktion notwendig – nämlich das Klicken des per E-Mail zugestellten Aktivierungsschlüssels. Aber keine Panik – so kompliziert es für manchen auch klingen mag, so einfach kann man es Dank des acts_as_state_machine-Plugins (mittlerweile umbenannt in AASM) in einer Rails-Applikation anwenden. Wir installieren das Plugin wie folgt:

$ ruby script/plugin install git://github.com/rubyist/aasm.git

Alternativ kann auch hier wieder das RubyGem verwendet werden:

$ sudo gem install rubyist-aasm

…welches dann wiederum konsequenterweise auch als Abhängigkeit in config/environment.rb definiert werden sollte:

config.gem 'rubyist-aasm'

AASM speichert den aktuellen Status eines Objektes in der Datenbank. Dazu erweitern wir das dem Automaten zugrundeliegende Model User um das Attribut status:

$ script/generate migration add_status_to_users status:string

Bevor wir die Migration anwenden, sollten wir noch einen Standardwert für das Attribut definieren. Das ist zwar nicht zwingend notwendig – gehört aber meines Erachtens nach zu einem sauberen Stil und trägt zur Wahrung der logischen Integrität der Daten bei.

class AddStatusToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :status, :string, :default => 'pending'
  end

  def self.down
    remove_column :users, :status
  end
end

$ rake db:migrate

Die eigentliche Definition des Automaten erfolgt im Model User (Listing 6).

Listing 6

 class User < ActiveRecord::Base

  acts_as_authentic

  include AASM

  attr_protected :status

  aasm_column :status
  aasm_initial_state :pending

  aasm_state :pending
  aasm_state :confirmed     

  aasm_event :confirm do
    transitions :to => :confirmed, :from => :pending
  end

end

assm_state definiert die beiden Zustände, die eine Registrierung haben kann. assm_event erzeugt automatisch die Instanzmethode :confirm!, die wir später aufrufen, wenn ein Benutzer den Bestätigungslink aufruft, um den gewünschten Zustandsübergang auszulösen. An dieser Stelle möchte ich auf die vielen zusätzlichen Funktionen des AASM-Plugins hinweisen, die u.a. neben der automatischen Bereitstellungen von zustandsspezifischen named_scopes auch die Ausführung bestimmter Aktionen beim Verlassen oder Eintreten eines bestimmten Zustands ermöglichen. Eine Vielzahl von zustandsorientierten Vorgängen lässt sich so in Web-Applikation hervorragend abbilden und sorgt auf diese Weise für gut lesbaren und sicheren Code.

„MagicColumns“, „MagicStates“ – nur Harry Potter fehlt

Authlogic verfügt über sog. „MagicColumns“ und „MagicStates“ – letzere sorgen auf magische Weise dafür, dass Authlogic bereits jetzt ohne unser Zutun mit dem endlichen Automaten zusammenarbeitet. Authlogic fragt bei jedem Login die Methoden active?, approved? und confirmed? ab – sofern sie existieren. Durch die Einführung unseres endlichen Automaten mit dem Zustand confirmed haben wir automatisch auch die Instanzmethode confirmed? erhalten. Bei unbestätigten Registrierungen gibt diese den Wert false zurück und veranlasst Authlogic, eine passende Fehlermeldung anzuzeigen. So wird verhindert, dass sich ein Benutzer ohne vorherige Bestätigung mit seinen Zugangsdaten anmelden kann.
Für die Erzeugung eines Aktivierungsschlüssels verwenden wir die „MagicColumn“ perishable_token, was übersetzt sinngemäß mit „temporäres Merkmal“ übersetzt werden kann. Temporär deswegen, weil Authlogic dieses Attribut bei jeder Aktualisierung des Benutzerobjektes verändert. Die Erweiterung erfolgt wie gewohnt mit einer Migration:

$ script/generate migration add_perishable_token_to_users perishable_token:string

Vor Anwendung dieser Migration passen wir auch hier die Migration noch einmal an, sodass das Vorhandensein eines Wertes für das neue Attribut forciert wird.

class AddPerishableTokenToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :perishable_token, :string, :null => :false
  end

  def self.down
    remove_column :users, :perishable_token
  end
end

$ rake db:migrate

Da es sich bei der Benutzerregistrierung zunächst um nichts anderes als die Erzeugung und Speicherung eines ActiveRecord-Objektes handelt, können wir wieder zu bekannten Mitteln greifen. Ein REST-konformer Controller (Listing 7):

$ script/generate controller users

…mit entsprechendem Eintrag in der config/routes.rb:

map.resources :users

…und einem dazugehörigen Formular (Listing 8) reichen schon aus – denn um die Validierung kümmert sich in der Standardkonfiguration bereits Authlogic.

Listing 7

class UsersController < ApplicationController

  before_filter :require_no_user

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:notice] = 'Thanks for signing up. We just sent you a confirmation email!'
      redirect_back_or_default root_url
    else
      render :new
    end
  end

  def confirm
    @user = User.pending.find_using_perishable_token(params[:confirmation_code])
    unless @user
      flash[:error] = 'Sorry, your activation code is invalid!'
    else
      @user.confirm!
      @user.reset_perishable_token!
      flash[:notice] = 'Great, your registration has been confirmed successfully!'
    end
    redirect_back_or_default root_url
  end
end

Listing 8

# app/views/users/new.html.erb

Register

< % form_for @user do |f| %> < %= f.error_messages %> < %= f.label :email %> < %= f.text_field :email %> < %= f.label :password %> < %= f.password_field :password %> < %= f.label :password_confirmation %> < %= f.password_field :password_confirmation %>
< %= f.submit 'Register!' %>
< % end %>

Um die Zustellung der Bestätigungsmail müssen wir uns allerdings selbst kümmern. Dazu erzeugen wir zunächst die ActionMailer-Klasse UserMailer (Listing 9):

$ script/generate mailer user_mailer

Listing 9

class UserMailer < ActionMailer::Base

  include ActionController::UrlWriter 

  def confirmation_code(user)
    from 	 'Foo Bar '
    recipients  user.email
    subject     'Please confirm your registration'
    body	 :user => user
    sent_on     Time.now
  end  

end

Wichtig ist dabei, dass wir das Modul ActionController::UrlWriter inkludieren und eine Domain in config/environment.rb als Grundlage für die UrlWriter-Methoden konfigurieren, damit wir den Bestätigungslink für das Mailer-Template (Listing 10) erzeugen können:

class ActionMailer::Base
  default_url_options[:host] = 'example.org'
end

Diese Notwendigkeit lässt sich mit der Tatsache erklären, dass der Prozess des E-Mail-Versands in einer MVC-Applikation keinen Zugriff auf einen Request (ActionController::AbstractRequest) hat, um Informationen über den aktuellen Hostnamen der Applikation zu bekommen. Wer möchte, kann daher für die verschiedenen Environments die passenden URLs in den dazugehörigen, separaten Konfigurationsdateien (z.B. config/environments/production.rb) konfigurieren.

Listing 10

# app/views/user_mailer/confirmation_code.erb

Hi,

please confirm your registration:

< %= confirmation_url :confirmation_code => @user.perishable_token %>

Thanks!

Dem aufmerksamen Leser ist sicherlich die Methode confirm im UsersController (Listing 7) aufgefallen, die ein Benutzerobjekt anhand des Attributs perishable_token aus dem Pool der unbestätigten Benutzer lädt. Damit ein Benutzer also später nach Klicken des Aktivierungslinks auf diese Methode geroutet wird, benötigten wir noch einen passenden Eintrag in der config/routes.rb:

map.confirmation 'confirmation/:confirmation_code',
                   :controller   => 'users',
                   :action       => 'confirm',
                   :conditions   => {:method => :get}

Bleibt nun noch der Versand der Bestätigungs-E-Mail nach Erzeugung eines Benutzerobjektes. Um diesen auszulösen, bedienen wir uns eines ActiveRecord-Observers (Listing 11):

$ script/generate observer user

Listing 11

class UserObserver < ActiveRecord::Observer

  def after_create(user)
    UserMailer.deliver_confirmation_code(user) if user.pending?
  end

end

Der UserObserver muss wie üblich in der config/environment.rb aktiviert werden:

config.active_record.observers = :user_observer

Wenn wir nun unsere Applikation starten und alles richtig gemacht haben, können sich neue Benutzer unter dem Menüpunkt Register (Abb. 1) selbstständig registrieren, bekommen nach Registrierung eine Bestätigungs-E-Mail (Abb. 2) und können sich nach erfolgreicher Aktivierung (Abb. 3) einloggen (Abb. 4), um ihre persönlichen Daten einzusehen (Abb. 5).

Abb.1

Abb.1

Abb.2

Abb.2

Abb.3

Abb.3

Abb.4

Abb.4

Abb.5

Abb.5

Where Is My Mind?

Twitter, YouTube, Flickr & Co. – wenn es schon schwer fällt, eine vollständige Liste aller etablierten Onlinedienste wiederzugeben, dann ist es kein Wunder, dass der ein oder andere Benutzer gelegentlich Schwierigkeiten hat, sich an die richtige Kombination aus Benutzername und Passwort für die jeweilige Plattform zu erinnern. Dieses Problem wird zudem dadurch verstärkt, dass einige Applikationen bei der Anforderung eines vergessenen Passworts (phpBB & Co.) selbst ein zufälliges Passwort generieren und es per E-Mail versenden. Genauso zweifelhaft wie das Versenden jeglicher Zugangsdaten per E-Mail in Bezug auf Sicherheit ist, so wenig benutzerfreundlich sind auch die meisten Mechanismen, mit denen man diesen Vorgang zunächst auslösen muß.
Dank der Freiheit, die Authlogic bietet, kann man selbst entscheiden, wie man diesem Problem begegnen möchte. Ich habe sehr gute Erfahrung damit gemacht, einem Benutzer an seine E-Mail-Adresse einen Link zu senden, mittels dessen er sein Passwort selbst neu vergeben kann. Und genau das werden wir jetzt implementieren, indem wir zunächst einen PasswortResetRequestsController (Listing 12) generieren:

$ script/generate controller password_reset_requests

Listing 12


class PasswordResetRequestsController < ApplicationController

  before_filter :require_no_user

  def create
    @user = User.find_by_email(params[:email])
    if @user
      @user.reset_perishable_token!
      UserMailer.deliver_password_reset_instructions
      flash[:notice] = 'Please check your email to get further information on resetting your password'
      redirect_to root_url
    else
      flash[:notice] = 'Sorry, there is no user with that email address'
      render :new
    end
  end  

end

Auch hier benötigen wir wieder ein Formular (Listing 13), damit der Benutzer seine E-Mail-Adresse angeben kann.

Listing 13

# app/views/password_reset_requests/new.html.erb

< % form_tag password_reset_requests_url do %>

  < %= label_tag :email %>
  < %= text_field_tag :email, params[:email] %>
< %= submit_tag 'Submit!' %> < % end %>

Damit das Routing auch funktioniert, konfigurieren wir noch eine Resource in der config/routes.rb:

map.resources :password_reset_requests, :except => [:index, :show, :destroy]

Zum Versand der E-Mail erweitern wir den bestehenden UserMailer um folgende Methode…

def password_reset_instructions(user)
  from 	       'Foo Bar '
  recipients  user.email
  subject     'How to reset your password'
  body	       :user => user
  sent_on     Time.now
end

…und fügen folgenden Inhalt für das zugehörige Template in die Datei app/views/user_mailer/password_reset_instructions.erb ein:

Hi,

you may reset your password by clicking the follwing link:

< %= edit_password_reset_request_url @user.perishable_token %>

Thanks!

Nun kann der Benutzer nach Klicken des Reset-Links eines neues Passwort vergeben (Listing 14). Und damit dieser Wunsch nicht unerfüllt bleibt, müssen wir zum Abschluß im Controller natürlich noch die Methoden edit und update implementieren (Listing 15). Nach erfolgreicher Aktualisierung des Passworts ist der Benutzer automatisch eingeloggt und wird auf seine persönliche Seiten weitergeleitet. Bequemer geht es nicht.

Listing 14

< % form_for @user, :url => password_reset_request_path do |f| %>

  < %= f.error_messages %>

  < %= f.label :password %>
  < %= f.password_field :password %>

  < %= f.label :password_confirmation %>
  < %= f.password_field :password_confirmation %>  
< %= f.submit 'Update my password' %>
< % end %>

Listing 15

# app/controllers/password_reset_requests.rb 

  def edit
    @user = User.find_by_perishable_token(params[:id])
  end 

  def update
    @user = User.find_by_perishable_token(params[:id]) 

    unless params[:user][:password].blank?
      @user.password              = params[:user][:password]
      @user.password_confirmation = params[:user][:password_confirmation]

      if @user.save
        flash[:notice] = 'Your password has been updated. Your are logged in.'
        redirect_to account_url
      else
        render :edit
      end
    else
      flash[:error] = 'Please enter your new password!'
      render :edit
    end
  end

OpenID, OAuth & Co – die Authlogic Add-Ons

Es gibt verschiedene Gründe, keinen eigenen Datensatz zur Authentifizierung etablieren zu wollen. Vielleicht möchte man auf eine bestehende LDAP-Infrastruktur aufsetzen, im Rahmen eines Lazy-Registration-Patterns eine Alternative in Form von OpenID zur Verfügung stellen oder aber eine der zahlreichen Authentifizierungs-APIs der Social-Networks (z.B. Facebook Connect, Twitter’s OAuth) verwenden. Authlogic ermöglicht diese und zukünftige Erweiterungen in Form von Add-Ons, die auf einer Public API aufsetzen.

Authlogic ist Kosmopolit!

Authlogic unterstützt die Rails Internationalization-API vollständig. Für diesen Artikel habe ich mich aus Gründen der Übersichtlichkeit gegen die Übersetzung ins Deutsche entschieden. Der Vollständigkeit halber möchte ich dennoch die verfügbaren Schlüssel zur Übersetzung, so wie sie im Plugin-Ordner unter lib/authlogic/i18n.rb beschrieben sind, aufzählen:

authlogic:
  error_messages:
    login_blank: can not be blank
    login_not_found: is not valid
    login_invalid: should use only letters, numbers, spaces, and .-_@ please.
    consecutive_failed_logins_limit_exceeded: Consecutive failed logins limit exceeded, account is disabled.
    email_invalid: should look like an email address.
    password_blank: can not be blank
    password_invalid: is not valid
    not_active: Your account is not active
    not_confirmed: Your account is not confirmed
    not_approved: Your account is not approved
    no_authentication_details: You did not provide any details for authentication.
  models:
    user_session: UserSession (or whatever name you are using)
  attributes:
    user_session: (or whatever name you are using)
      login: login
      email: email
      password: password
      remember_me: remember me

Whatcha Gonna Do when they come for you?

Brute-Force, Session-Fixation & Co. gehören zum Standardrepertoire der bösen Jungs. Authlogic ist sich der Gefahren bewusst und stellt dem Entwickler probate Mittel gegen diese Angriffsmuster zu Verfügung. Eine Diskussion und nähere Erläuterung würde den Rahmen des Artikels endgültig sprengen, weswegen ich an dieser Stelle auf das Studium der Sources verweisen möchte. Besonders von Interesse sind dabei z.B. lib/session/brute_force_protection.rb und die Dateien in lib/authlogic/crypto_providers. In jedemfall empfehle ich aber, die zusätzliche „MagicColumn“ password_salt für unsere Beispielapplikation zu erzeugen – diese erschwert das Entschlüsseln der Passwörter für den Fall, dass ein Angreifer Zugriff auf die Datenbanktabelle users erhält. Ebenfalls einen Blick Wert ist das SslRequirement Plugin von David Heinemeier Hansson, um sensible Benutzerinformationen ausschließlich über eine verschlüsselte und verifizierte Verbindung zu übertragen.

acts_as_restful_authentication – Authlogic Inkognito

„Wandel und Wechsel liebt, wer lebt.“ – ob Richard Wagner auch an dieser Weisheit festgehalten hätte, wenn er Software-Entwickler geworden wäre? Ein Wechsel einer (funktionierenden) Komponente innerhalb einer Applikation bringt oftmals erheblichen Aufwand und nicht selten auch Ärger mit sich, weshalb sich in dieser Hinsicht der gutgemeinte Ratschlag „Never change a running system“ schon eher etabliert hat. Wer doch den Schritt von restful_authentication zu Authlogic in einer produktiven Applikation wagen möchte, dem sei der Artikel des Authlogic-Urhebers Ben Johnson zu diesem Thema ans Herz gelegt.

Quellcode Download

Authlogic Example App (0,28 MB), Ruby on Rails 2.3.2

Dieser Artikel ist unter dem Titel „Rein oder nicht rein – das ist hier die Frage“ im Fachmagazin RailsWay (5/09) erschienen.

qmail und ActionMailer 0

Aus irgendeinem Grund wollte eine Webapp keine E-Mails an Gmail-Adressen zustellen. Da Probleme mit ActionMailer selbst in Rails eher selten vorkommen, lohnt es sich, bei solchen systematischen Zustellungsproblemen, direkt die Maillogs zu checken.

Connected_to_209.85.218.14_but_sender_was_rejected./Remote_host_said:_555_5.5.2_Syntax_error

Etwas früher war zu erkennen, dass die vom qmail-remote-handler verwendet from-Adresse eine sehr seltsame Syntax hatte…

plesk qmail-remote-handlers[32214]: from=example <noreply@example

Der entsprechende Teil im ActionMailer war jedoch korrekt konfiguriert, ein Dump der Mailsource vor Versand war einwandfrei RFC-konform und auch die Header der zugestellten E-Mails waren unauffällig.

Scheinbar kommt qmail nicht mit der Notation eines Namens nebst E-Mail-Adresse klar. Die Lösung des Problems liegt in der Konfiguration eines Return-Path-Headers, der in diesem Fall auch direkt als Envelope-From verwendet wird.

Was Dave Lombardo mit Trabayo zu hat und warum der Countdown läuft 0

Vor einiger Zeit habe ich über Trabayo aus Entwicklersicht berichtet. Passend zum morgigen Release ist ein interessanter Artikel von Thomas über Trabayo in der neue Ausgabe (6.09) des Rails-Fachmagazins RailsWay zu lesen. Der Artikel illustriert den frischen Blick auf den Status Quo und die dazugehörigen Portion Innovationswillen und Mut aus Konzepter-/Unternehmersicht, der diesem Projekt nicht unwesentlich zum Erfolg beigetragen hat.
Ich habe das ein oder andere Projekt der Post-Dot.com-Ära in den letzten 5 Jahren kommen und gehen sehen – und einige davon haben es nicht einmal auf die Beine geschafft. Für Trabayo hingegen ist morgen der große Tag. Und genauso entspannt und authentisch Karo, Meike, Marius und Thomas während der Entwicklung gewesen sind, so cool ist der Name des ersten Releases: Dave Lombardo. Im Rahmen des likemind wird Trabayo im Berliner Café Ick koof mir Dave Lombardo wenn ick reich bin präsentiert. Der erste Kaffee geht dabei auf’s Team.

Für alle anderen, die nicht kommen können, geht es morgen (16. Oktober 2009) ab 11 Uhr los. Auf www.trabayo.com kannst Du Deine Talente und Fähigkeiten präsentieren und nebenbei noch eine Free-Forever-Mitgliedschaft abstauben.

Elektronische Signaturen 2009 2

Vor knapp 10 Jahren wurde mit der EG-Richtlinie 1999/93/EG („Signaturrichtlinie“) der Grundstein für elektronischen Signaturen gelegt. Das im allgemeinem Sprachgebrauch auch als „digitale Unterschrift“ bekannte Pendant zur handschriftlichen Unterzeichnung von Dokumenten sollte den juristisch notwendigen Schulterschluss im digitalen Geschäftsverkehr und später für das sogenannte E-Government schaffen.

Elektronische Rechnungen

Im Zuge der Automatisierung der Buchhaltung meines Informationstechnologieunternehmens war ich 2008 zum ersten Mal selbst mit diesem Thema konfrontiert. Da ich vorwiegend Geschäftskunden zu meinem Kundenstamm zähle, müssen per E-Mail zugestellte Rechnungen eine digitale Signatur tragen. Die Signatur erfüllt dazu die Anforderungen einer fortgeschrittenen elektronischen Signatur gemäß § 2 Nr. 2 SigG bzw. qualifizierten elektronischen Signatur gemäß § 2 Nr. 3 SigG und berechtigt damit das rechnungserhaltende Unternehmen zum Abzug der Vorsteuer gemäß §14 UStG.

Lohnt sich das?

Soweit die Theorie. In der Praxis sind eine Reihe von Auflagen zu beachten, damit die Signaturen nicht nur im technischen Sinne die Anforderungen erfüllen, sondern auch einer juristischen/fiskalischen Prüfung standhalten. Aufgrund der fehlenden Zertifizierung zur Bestätigung der Konformität zu SigG / SigV war die Entwicklung einer eigenen Signaturkomponente oder die Integration von OpenSC / OpenSSL nicht möglich. Ich habe mich daher für die Lizensierung der Anwendung SecSignerServer der SecCommerce GmbH entschieden.
Die Kosten, die ich bis zu diesem Zeitpunkt für Softwarelizenzen, Kartenlesegerät (ReinerSCT cyberjack e-com) und Signaturkarte (D-Trust multicard 2048 Bit) investiert habe, betrugen knapp 1500,00 €. Es wird deutlich, dass der postalische Versand der Rechnungen wirtschaftlich günstiger gewesen wäre. Für durchschnittlich 10 Rechnungen / Tag, die durch die bereits vorhandene vollautomatisierte Fakturierung erstellt wurden, lohnte der Aufwand also nicht unbedingt. Dennoch macht eine derartige Vollautomatisierung für kleine Unternehmen Sinn, sodass die knappen „Human Resources“ nicht durch derartige Tätigkeiten gebunden werden.
Nach 2 Monaten Entwicklungsarbeit war die Integration abgeschlossen und das System (basierend auf Ruby on Rails) umgestellt, sodass alle Kunden ihre Rechnungen per E-Mail bekommen und die Debitorenkonten mittels FinTS/HBCI-Anbindung synchronisiert werden.

Elektronische Steuererklärung

Durch diese Umstellung hat sich eine weitere, sinnvolle Anwendung der Signaturkarte ergeben. Bisher sind nicht unerhebliche Kosten für den Steuerberater angefallen, der jedes Quartal u.a. ein umfangreiches Rechnungsjournal auswerten musste, um die Erkenntnisse in Form einer Umsatzsteuervoranmeldung dem Finanzamt vorzutragen. Ich habe nun die Zeit, einmal im Quartal meine Kostenseite und die automatisch erfassten Einnahmen zu analysieren, um selbst mittels ElsterFormular eine entsprechende Umsatzsteuervoranmeldung einzureichen. Das spart Kosten und schafft zudem einen guten Überblick über das eigene Unternehmen. Nicht zuletzt hat diese Tätigkeit teilweise eine Art Controlling-Charakter bekommen, der an verschiedenen Stellen wirtschaftliches Optimierungspotential aufzeigt.

Buy vs. Build Decision

Optimierungspotential gibt es aber auch in technischer Hinsicht.
So würde ich mir wünschen, dass der Zertifizierungsprozess eigener Software zur Bestätigung der Konformität zu SigG / SigV vereinfacht wird. So praktisch die Software von SecCommerce auch sein mag – ich hätte eine elegantere Lösung in Form eines REST-Interfaces auf Ruby-on-Rails-Basis mit nativem Zugriff auf ISO 7816 SmartCard-Interfaces bevorzugt. Übrigens: zum damaligen Zeitpunkt war JRuby noch nicht produktiv einsetzbar – denn ansonsten hätte ich mich für SecSignerAPI als Signaturanwendungskomponente entschieden, deren Integration in eigene Software eine erneute Zertifizierung optional macht.

Erfahrungsbericht: ElsterFormular / Signaturkarte

Was mich ein wenig stutzig macht, war die komplizierte Installation der Middleware für den Zugriff auf die Signaturkarte aus ElsterFormular heraus. Die Installation des ReinerSCT cyberjack e-com Kartenlesegeräts ist unter Windows[1] kein Problem. Die Initialisierung der D-Trust multicard Signaturkarte war ebenfalls mit wenigen Mausklicks erledigt. Download und Installation von ElsterFormular („Bundestrojaner“) ist auch nicht der Rede wert. Die Ahnungslosigkeit des Supports von D-Trust und REINER SCT, sowie die Unerreichbarkeit der Elster-Hotline schon. Wählt man beim Übertragen der Steuererklärung an das Finanzamt die Signaturkarte „D-Trust qualified“ unter ELSTER-Plus aus, dann erhält man die folgende Fehlermeldung:

Die Datei “Personal.dll” konnte im Verzeichnis C:\\Windows\system32\ nicht gefunden werden.

Diese Datei wurde zusammen mit dem Kartenleser auf Ihrem PC installiert. Sie ist für den Zugriff auf Ihre Signaturkarte notwendig. Bitte geben Sue den Ort dieser Datei an.

Da ich Windows als unnötiges Übel meide, bin ich selbst ein wenig überfragt gewesen. Klar – DLL sagt mir was. Das ist das, was unter Windows immer kaputt geht oder, sowie hier, fehlt. Also den Support kontaktiert. Als erstes hab ich mich an die Elster-Hotline gewendet – die Entwickler, so dachte ich, sind in diesem Fall die besten Ansprechpartner. Aber nach 4 Versuchen, die jeweils nach 15 Minuten durch Zwangstrennung unterbrochen wurden, hab ich aufgegeben. Wer masochistisch veranlagt ist, sollte sich die Warteschleife mal zu Gemüte führen: 01805 / 235055.
Als nächstes habe ich die Fehlermeldung wörtlich genommen – ein Verhalten, dass man sich selbst als Entwickler von seinen Anwendern immer wieder wünscht. Ein Anruf bei REINER SCT, deren Support übrigens schnell, kompetent und direkt erreichbar ist, hat mich nicht weitergebracht. Dort sagte man mir, dass entsprechende Dateien signaturkartenspezifisch seien und niemals zusammen mit dem Kartenlesegerät installiert würden. Und da ich die Signaturkarte von D-Trust hatte, rief ich dann eben dort an – nachdem ich auf deren Website nichts passendes gefunden hatte. Denn das vorherige Lesen der FAQ wünscht man sich von seinen Kunden ebenfalls – und da wollte ich mit gutem Beispiel vorangehen.

Ohne Middleware geht nichts

Nexus Personal als kostenpflichtige Middleware. Die Software kann nur per E-Mail bestellt werden und wird dann postalisch auf einem Datenträger gegen Rechnung versendet – Downloadversionen, Kreditkartenzahlung & Co. sind hier nicht möglich. Und da andere Software nicht offiziell unterstützt wird… hatte ich ganze 3 Tage später die Möglichkeit, Nexus Personal zu installieren, um endliche meine Umsatzsteuervoranmeldung einzureichen.
Die Fehlermeldung konnte ich dann dadurch beheben, dass ich die Datei C:\\Programme\Personal\bin\personal.dll manuell nach C:\\Windows\system32\Personal.dll kopiert habe. Herausfinden musste ich das allerdings selbst – der D-Trust-Support war in dieser Hinsicht leider ratlos. Ich hoffe daher, dass Google beim Suchen dieser Fehlermeldung meinen Artikel anzeigt. Danach konnte ich ElsterFormular starten, die gespeicherte Steuererklärung öffnen und die Übertragung starten. Verärgert hingegen hatte mich dann die nächste Fehlermeldung nach Eingabe der Card-PIN:

Die Datenübertragung ist gescheitert.
Dem von Ihnen verwendeten Zertifikat konnte kein Account bei ElsterOnline zugeordnet werden. Sie verwenden ein Zertifikat, das nicht bei ElsterOnline registriert/ von ElsterOnline ausgestellt wurde.
Fehlercode: 080015019

Registrierung bei ElsterOnline

Man muß sich scheinbar nochmal registrieren, um seine Identität zweifelsfrei an Steuernummer und Signaturkarte zu binden. Das Wort Bürokratie kann ich mir an dieser Stelle nicht verkneifen. Nun gut, ein bißchen Geduld war noch übrig. Browser auf und ins ElsterOnline-Portal zur Registrierung navigiert. ElsterBasis, ElsterSpezial, ElsterPlus mit Preisangaben von kostenlos über 41 € bis hinzu zwischen 50 € und 150 €. Wofür die Preise stehen ist nicht ersichtlich. Ich vermute, das die Registrierungen prinzipiell kostenlos und damit nur die zu erwartenden Zusatzkosten für Hardware & Co. gemeint sind.
ElsterPlus ist laut Übersichtsseite die richtige Wahl, wenn man eine bereits vorhandene Signaturkarte verwenden möchte.

Signaturkarte für Authentifizierung
Verfügt der Benutzer über eine von ELSTER unterstützte Signaturkarte für Authentifizierung, so kann er diese auch im Rahmen des ElsterOnline-Portals einsetzen.

Signaturkarten für Authentifizierung stellen den elektronischen Ersatz Ihrer handschriftlichen Unterschrift dar und werden z. B. von Banken ausgegeben. Ein mit einer Signaturkarte für Authentifizierung signiertes Dokument wird als rechtsverbindlich angesehen. Die Finanzverwaltung fordert bei der Verwendung von Signaturkarten für Authentifizierung ein Mindestmaß an Sicherheit, das in der ELSTER-Policy festgehalten wurde.

Die persönliche Registrierung ist auf den ersten Blick einfach und übersichtlich gehalten und daher schnell ausgefüllt. Was folgt, ist die obligatorische E-Mail-Bestätigung zur Verifizierung. Danach folgt ein Hinweis, der zusammen mit einer Aktivierungs-ID kommt:

Die Aktivierungs-ID benötigen Sie für den zweiten Schritt der Registrierung zusammen mit dem Aktivierungs-Code, den Sie gesondert per Post erhalten. Bewahren Sie deshalb diese E-Mail unbedingt auf, bis auch der Brief mit dem Aktivierungs-Code bei Ihnen vorliegt. Für die Zusendung des Aktivierungs-Codes wird die zu Ihrer Steuernummer gespeicherte Adresse verwendet.

Warten wir also ab. 14 Tage kann das dauern.

Nach 6 Tagen ist der Aktivierungs-Code vom Finanzamt per Post angekommen. Um meine Registrierung abzuschließen, habe ich entsprechend des Schreibens meine Aktivierungs-ID nebst des Aktivierungs-Codes auf der Website eingeben wollen. Die folgende Fehlermeldung, verursacht durch ein bekanntes Problem mit Java-Version 6 Update 15, erforderte zunächst die Anpassung der Java-Plugin-Konfiguration.

Ich habe beim Versuch, mich ins Portal einzuloggen einen Hinweis auf einen Fehler in der Version Java 6 Update 15 von Sun Microsystems erhalten. Wie kann ich diesen Fehler umgehen?

Durch einen Fehler in der am 6.8.2009 veröffentlichten Version Java 6 Update 15 kann es sein, dass kein Login im Portal mehr möglich ist. Diesen Fehler können Sie umgehen, indem Sie im Java Control Panel (in der Systemsteuerung unter “Java” zu finden) unter “Erweitert” – >
“Java-Plug-In” das Häckchen neben “Java-Plug-In der nächsten Generation aktivieren” entfernen und anschließend den Browser neu starten.

Anwender von Java 6 Update 14 oder älter sind nicht betroffen. Die genaue Version kann im Java Control Panel unter “Allgemein” -> “Anwendungsinfo” ermittelt werden. Die Zahl hinter dem Begriff “Aktualisierung” entspricht der Nummer des Updates.

Die Fehlermeldung enthielt folgenden Stacktrace:

Exception in thread "AWT-EventQueue-2" java.lang.InternalError: couldn't create component peer
(…)
java.lang.NoClassDefFoundError: de/elster/portal/applet/ZoomApplet
(…)
Caused by: java.lang.ClassNotFoundException: de.elster.portal.applet.ZoomApplet
(…)
Caused by: java.io.IOException: open HTTP connection failed:https://www.elsteronline.de/eportal/applet/de/elster/portal/applet/ZoomApplet.class
(…)
Ausnahme: java.lang.NoClassDefFoundError: de/elster/portal/applet/ZoomApplet

Nachdem ich der obigen Anweisung zur Fehlerbehebung gefolgt bin, konnte ich die Registrierung abschließen. Trotzdem kann ich mich nicht gegen den Eindruck wehren, dass beim Entwurf von ElsterOnline der Usability-Aspekt an (vermutlich) juristischen Rahmenbedingungen gescheitert ist.
Gibt man nicht binnen 15 Sekunden seinen Card-PIN ein, bricht das Applet mit einer Fehlermeldung ab. Gibt man ihn ein, so muß man die Eingabe beim Login ein weiteres Mal wiederholen. Fast jeder Schritt, den man nach Login ausführen möchte, erfordert ebenfalls die Eingabe der Card-PIN. Das Lesen von Nachrichten ist auch alles andere als benutzerfreundlich:

  • Klick auf die Nachrichten im Nachrichteneingang
  • Eingabeaufforderung der Card-PIN
  • Download der Nachricht als PDF oder HTML
  • Versuch des Java-Applets, die lokal gespeicherte Datei zum Anzeigen zu öffnen

Als (ehemaliger) Nutzer des Software-Zertifikats war ich dieses Vorgehen nebst Mehrfacheingabe der PIN schon gewohnt. Aber immerhin bekommt man jetzt auch die Möglichkeit, eine Steuerkontenabfrage zu machen. Zumindest dann, wenn man den dazu notwendigen Zusatzantrag ausfüllt, der wiederum erst bearbeitet werden muß.

[1] Unter Mac OS X ist das manuelle, nachträgliche Entfernen einiger installierter Treiberkomponenten notwendig

TRABAYO – was kannst Du, das andere brauchen? 1

Anfang des Jahres hat mich Thomas von PANORAMA3000 für ein Projekt engagiert begeistert, welches sich langsam aber sicher der Public-Beta-Phase nähert.

Du hast ein Talent, vielleicht ein noch verborgenes, mit dem du etwas verdienen möchtest? Du hast Fähigkeiten, die jemand anders gut gebrauchen kann? Dann hör auf zu kellnern und mach die Cocktails einfach selbst.

Auf www.trabayo.com kannst Du Dich bereits jetzt registrieren, um schon bei den ersten Testläufen aktiv dabei zu sein. Neben der Möglichkeit, das Portal konstruktiv mitzugestalten, wirst Du zusätzlich mit einer lebenslangen Premium-Mitgliedschaft belohnt.

Das Projekt ist auch aus Entwicklersicht ein Leckerbissen – Thomas, Marius und Karolin haben neben einem erstklassigen Konzept und einem frischen Blick auf den Status Quo die dazugehörigen Portion Innovationswillen und Mut, um eine solide Entwicklung im Rahmen eines agilen Entwicklungsmodells zu ermöglichen. Eine umfangreiche Test-Suite und Continous-Integration/Release-Management bilden dabei die technische Grundlage für ein tägliches Deployment in ein Multistaging-Environment auf Basis von Phusion Passenger™  und Ruby Enterprise Edition

Semantic Web als Bestandteil des technischen Kernkonzeptes verspricht eine Menge Abwechslung und spannende Entwicklungsphasen, die weit über das bloße Anwenden der bewährten Ruby-on-Rails-Pattern hinaus gehen.

Das Trabayo-Weblog informiert dabei regelmäßig über interessante Neuigkeiten rund um das Projekt – es lohnt sich!