diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb
index b1500d4..64390a0 100644
--- a/app/controllers/account_controller.rb
+++ b/app/controllers/account_controller.rb
@@ -19,11 +19,19 @@ class AccountController < ApplicationController
   helper :custom_fields
   include CustomFieldsHelper   
   
+  @cas_initialized = false
+  class << self; attr_accessor :cas_initialized; end
+
   # prevents login action to be filtered by check_if_login_required application scope filter
   skip_before_filter :check_if_login_required
 
   # Login request and validation
   def login
+    # If we are forcing CAS authentication, bypass everything else and go to it.
+    if Setting.cas? && Setting.cas_force != '0'
+      cas_authenticate
+    end
+
     if request.get?
       # Logout user
       self.logged_user = nil
@@ -133,6 +141,54 @@ class AccountController < ApplicationController
     redirect_to :action => 'login'
   end
   
+  def cas_authenticate
+    unless self.class.cas_initialized
+      CASClient::Frameworks::Rails::Filter.configure(
+        :cas_base_url => Setting.cas_base_url
+      )
+      self.class.cas_initialized = true
+    end
+
+    CASClient::Frameworks::Rails::Filter.filter(self) unless session[:cas_user]
+    if session[:cas_user]
+      user = User.find_or_initialize_by_login(session[:cas_user])
+      if user.new_record?
+        # Self-registration off
+        redirect_to(home_url) && return unless Setting.self_registration?
+
+        # Create on the fly
+        user.login = session[:cas_user]
+        user.mail = session[:cas_user] + Setting.cas_email_suffix
+        user.firstname = session[:cas_user]
+        user.lastname = session[:cas_user]
+        user.random_password
+        user.status = User::STATUS_REGISTERED
+
+        case Setting.self_registration
+        when '1'
+          register_by_email_activation(user) do
+            onthefly_creation_failed(user)
+          end
+        when '3'
+          register_automatically(user) do
+            onthefly_creation_failed(user)
+          end
+        else
+          register_manually_by_administrator(user) do
+            onthefly_creation_failed(user)
+          end
+        end
+      else
+        # Existing record
+        if user.active?
+          successful_authentication(user)
+        else
+          account_pending
+        end
+      end
+    end
+  end
+
   private
 
   def password_authentication
@@ -189,7 +245,7 @@ class AccountController < ApplicationController
       end
     end
   end
-  
+
   def successful_authentication(user)
     # Valid user
     self.logged_user = user
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 16f59be..92ce65c 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -143,6 +143,10 @@ class Setting < ActiveRecord::Base
   def self.openid?
     Object.const_defined?(:OpenID) && self[:openid].to_i > 0
   end
+
+  def self.cas?
+    Object.const_defined?(:CAS) && self[:cas].to_i > 0
+  end
   
   # Checks if settings have changed since the values were read
   # and clears the cache hash if it's the case
diff --git a/app/views/account/login.rhtml b/app/views/account/login.rhtml
index 6edfb44..7afc216 100644
--- a/app/views/account/login.rhtml
+++ b/app/views/account/login.rhtml
@@ -25,6 +25,13 @@
     </td>
 </tr>
 <tr>
+  <% if Setting.cas? %>
+    <tr>
+        <td align="left">
+            <%= link_to l(:label_cas_login), :controller => 'account', :action => 'cas_authenticate' %>
+        </td>
+    </tr>
+  <% end %>
     <td align="left">
         <% if Setting.lost_password? %>
             <%= link_to l(:label_password_lost), :controller => 'account', :action => 'lost_password' %>
diff --git a/app/views/settings/_authentication.rhtml b/app/views/settings/_authentication.rhtml
index eb51ee9..8f1a718 100644
--- a/app/views/settings/_authentication.rhtml
+++ b/app/views/settings/_authentication.rhtml
@@ -16,6 +16,14 @@
 
 <p><%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %></p>
 
+<p><%= setting_check_box :cas, :disabled => !Object.const_defined?(:CAS) %></p>
+
+<p><%= setting_text_field :cas_base_url, :disabled => !Object.const_defined?(:CAS), :size => 50 %></p>
+
+<p><%= setting_text_field :cas_email_suffix, :disabled => !Object.const_defined?(:CAS), :size => 50 %></p>
+
+<p><%= setting_check_box :cas_force, :disabled => !Object.const_defined?(:CAS) %></p>
+
 <p><%= setting_check_box :rest_api_enabled %></p>
 </div>
 
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 2ee57bc..8cc6704 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -321,6 +321,10 @@ en:
   setting_file_max_size_displayed: Max size of text files displayed inline
   setting_repository_log_display_limit: Maximum number of revisions displayed on file log
   setting_openid: Allow OpenID login and registration
+  setting_cas: Use CAS login and registration
+  setting_cas_base_url: CAS server base URL
+  setting_cas_email_suffix: Default email suffix for CAS users
+  setting_cas_force: ONLY allow login using CAS (this disables normal login)
   setting_password_min_length: Minimum password length
   setting_new_project_user_role_id: Role given to a non-admin user who creates a project
   setting_default_projects_modules: Default enabled modules for new projects
@@ -447,6 +451,7 @@ en:
   label_register: Register
   label_login_with_open_id_option: or login with OpenID
   label_password_lost: Lost password
+  label_cas_login: Login using CAS
   label_home: Home
   label_my_page: My page
   label_my_account: My account
diff --git a/config/settings.yml b/config/settings.yml
index cebfbb5..2325e2e 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -180,3 +180,11 @@ start_of_week:
   default: ''
 rest_api_enabled:
   default: 0
+cas:
+  default: 0
+cas_base_url:
+  default: ''
+cas_email_suffix:
+  default: ''
+cas_force:
+  default: 0
