diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb
index fe44740a46588922093640d73070658347fd469e..2e280dac93f4ac110edb97564d4e1fe30d0c24f8 100644
--- a/app/controllers/account_controller.rb
+++ b/app/controllers/account_controller.rb
@@ -46,24 +46,10 @@ class AccountController < ApplicationController
       self.logged_user = nil
     else
       # Authenticate user
-      user = User.try_to_login(params[:username], params[:password])
-      if user.nil?
-        # Invalid credentials
-        flash.now[:error] = l(:notice_account_invalid_creditentials)
-      elsif user.new_record?
-        # Onthefly creation failed, display the registration form to fill/fix attributes
-        @user = user
-        session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id }
-        render :action => 'register'
+      unless using_open_id?
+        password_authentication
       else
-        # Valid user
-        self.logged_user = user
-        # generate a key and set cookie if autologin
-        if params[:autologin] && Setting.autologin?
-          token = Token.create(:user => user, :action => 'autologin')
-          cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
-        end
-        redirect_back_or_default :controller => 'my', :action => 'page'
+        open_id_authenticate(params[:openid_url])
       end
     end
   end
@@ -191,4 +177,59 @@ private
       session[:user_id] = nil
     end
   end
+  
+  def password_authentication
+    user = User.try_to_login(params[:username], params[:password])
+    if user.nil?
+      # Invalid credentials
+      flash.now[:error] = l(:notice_account_invalid_creditentials)
+    elsif user.new_record?
+      # Onthefly creation failed, display the registration form to fill/fix attributes
+      @user = user
+      session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id }
+      render :action => 'register'
+    else
+      # Valid user
+      successful_authentication(user)
+    end
+  end
+
+  
+  def open_id_authenticate(openid_url)
+    user = nil
+    authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
+      if result.successful?
+        user = User.find_or_initialize_by_identity_url(identity_url)
+        if user.new_record?
+          # Create on the fly
+          # TODO: name
+          user.login = registration['nickname']
+          user.mail = registration['email']
+          user.save
+        end
+        
+        user.reload
+        if user.new_record?
+          # Onthefly creation failed, display the registration form to fill/fix attributes
+          @user = user
+          session[:auth_source_registration] = {:login => user.login, :identity_url => identity_url }
+          render :action => 'register'
+        else
+          successful_authentication(user)
+        end
+      end
+    end
+  end
+  
+  def successful_authentication(user)
+    # Valid user
+    self.logged_user = user
+    # generate a key and set cookie if autologin
+    if params[:autologin] && Setting.autologin?
+      token = Token.create(:user => user, :action => 'autologin')
+      cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
+    end
+    redirect_back_or_default :controller => 'my', :action => 'page'
+  end
+
 end
diff --git a/app/views/account/login.rhtml b/app/views/account/login.rhtml
index d8c1f313f5dfd0fab46d486e93eb11286865c51d..d7a27821e05cc54271973e3bb52387257c7e21a9 100644
--- a/app/views/account/login.rhtml
+++ b/app/views/account/login.rhtml
@@ -10,6 +10,10 @@
     <td align="right"><label for="password"><%=l(:field_password)%>:</label></td>
     <td align="left"><%= password_field_tag 'password', nil, :size => 40 %></td>
 </tr>
+<tr>
+  <td align="right"><label for="openid_url"><%=l(:field_identity_url)%></label></td>
+  <td align="left"><%= text_field_tag "openid_url" %></td>
+</tr>
 <tr>
     <td></td>
     <td align="left">
diff --git a/app/views/account/register.rhtml b/app/views/account/register.rhtml
index 45719f055c3466fd0539a279158d36ea0925cdf6..71367e9b9d463094a9dd30d784c07be9ad2dd9b2 100644
--- a/app/views/account/register.rhtml
+++ b/app/views/account/register.rhtml
@@ -1,4 +1,4 @@
-<h2><%=l(:label_register)%></h2>
+<h2><%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url %></h2>
 
 <% form_tag({:action => 'register'}, :class => "tabular") do %>
 <%= error_messages_for 'user' %>
@@ -29,6 +29,9 @@
 <p><label for="user_language"><%=l(:field_language)%></label>
 <%= select("user", "language", lang_options_for_select) %></p>
 
+<p><label for="user_identity_url"><%=l(:field_identity_url)%></label>
+<%= text_field 'user', 'identity_url'  %></p>
+
 <% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %>
 	<p><%= custom_field_tag_with_label :user, value %></p>
 <% end %>
diff --git a/app/views/my/account.rhtml b/app/views/my/account.rhtml
index ef5b222e4efda6551d6b477f7f4f6f8e330a29f4..2fa91afb448bc9c42361355214a5c8211de491e6 100644
--- a/app/views/my/account.rhtml
+++ b/app/views/my/account.rhtml
@@ -15,6 +15,7 @@
 <p><%= f.text_field :lastname, :required => true %></p>
 <p><%= f.text_field :mail, :required => true %></p>
 <p><%= f.select :language, lang_options_for_select %></p>
+<p><%= f.text_field :identity_url  %></p>
 
 <% @user.custom_field_values.select(&:editable?).each do |value| %>
 	<p><%= custom_field_tag_with_label :user, value %></p>
diff --git a/app/views/users/_form.rhtml b/app/views/users/_form.rhtml
index 799ebde476b275e8b8f3d0cb30b2f593b57c29e5..1579ea53b9313fc8fd9e4fe1b8e4abeec111b329 100644
--- a/app/views/users/_form.rhtml
+++ b/app/views/users/_form.rhtml
@@ -7,6 +7,7 @@
 <p><%= f.text_field :lastname, :required => true %></p>
 <p><%= f.text_field :mail, :required => true %></p>
 <p><%= f.select :language, lang_options_for_select %></p>
+<p><%= f.text_field :identity_url  %></p>
 
 <% @user.custom_field_values.each do |value| %>
 	<p><%= custom_field_tag_with_label :user, value %></p>
diff --git a/config/routes.rb b/config/routes.rb
index 475d447be8144a4de787da8992b14179eb9874a2..d20bc3c9f05053fd89553ad7031a67fb139d3c4e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -255,4 +255,6 @@ ActionController::Routing::Routes.draw do |map|
   # Install the default route as the lowest priority.
   map.connect ':controller/:action/:id'
   map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
+  # Used for OpenID
+  map.root :controller => 'account', :action => 'login'
 end
diff --git a/lang/en.yml b/lang/en.yml
index 246bfb13ef72e941fb37a2470ecfa7b858c07ea5..a75a529902071641d54d39aaee6ddee175612a45 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -147,6 +147,7 @@ field_mail_notification: Email notifications
 field_admin: Administrator
 field_last_login_on: Last connection
 field_language: Language
+field_identity_url: OpenID URL
 field_effective_date: Date
 field_password: Password
 field_new_password: New password
@@ -332,6 +333,7 @@ label_information: Information
 label_information_plural: Information
 label_please_login: Please log in
 label_register: Register
+label_login_with_open_id_option: or login with OpenID
 label_password_lost: Lost password
 label_home: Home
 label_my_page: My page
diff --git a/public/images/openid-bg.gif b/public/images/openid-bg.gif
new file mode 100644
index 0000000000000000000000000000000000000000..e2d8377db023a3915cc9e8c2f1f5c7462622f0a1
Binary files /dev/null and b/public/images/openid-bg.gif differ
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 02c4a8b1bb797712332ea153319d6edf09d61272..653ae152fbf3de82d4338db68afbf24a27c52a2e 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -69,6 +69,8 @@ html>body #content { min-height: 600px; }
 #login-form table td {padding: 6px;}
 #login-form label {font-weight: bold;}
 
+input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
+
 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
 
 /***** Links *****/