Permalink
Browse files

Httpclient dependency dropped

  • Loading branch information...
1 parent b502675 commit da7cfcceca5fe8d3f5d44b82f7ec9b2d24872480 @mirek mirek committed May 10, 2010
Showing with 132 additions and 99 deletions.
  1. +2 −1 README.mkdn
  2. +130 −98 lib/redmine_cas.rb
View
3 README.mkdn
@@ -7,7 +7,8 @@ Install and configure plugin to delegate login/logout actions to your CAS server
Tested with Redmine 0.9.x
sudo gem install rubycas-client
- sudo gem install httpclient (use >= 2.1.5.2 as some older versions have SSL bugs)
+
+As of version 0.3 httpclient dependency has been dropped.
# Installation & Configuration
View
228 lib/redmine_cas.rb
@@ -1,38 +1,47 @@
-require 'httpclient'
require 'casclient'
require 'casclient/frameworks/rails/filter'
+require 'socket'
+require 'timeout'
-Redmine::Plugin.register :redmine_cas do
- name "CAS Authentication"
- author 'Mirek Rusin'
- description "CAS single sign-on service authentication support. After configuring plugin login/logout actions will be delegated to CAS server."
- version '0.0.2'
+if defined?(Redmine)
+ Redmine::Plugin.register :redmine_cas do
+ name "CAS Authentication"
+ author 'Mirek Rusin'
+ description "CAS single sign-on service authentication support. After configuring plugin login/logout actions will be delegated to CAS server."
+ version '0.0.3'
- menu :account_menu,
- :login_without_cas,
- {
- :controller => 'account',
- :action => 'login_without_cas'
- },
- :caption => :login_without_cas,
- :after => :login,
- :if => Proc.new { RedmineCas.ready? && RedmineCas.get_setting(:login_without_cas) && !User.current.logged? }
+ menu :account_menu,
+ :login_without_cas,
+ {
+ :controller => 'account',
+ :action => 'login_without_cas'
+ },
+ :caption => :login_without_cas,
+ :after => :login,
+ :if => Proc.new { RedmineCas.ready? && RedmineCas.get_setting(:login_without_cas) && !User.current.logged? }
- settings :default => {
- :enabled => false,
- :cas_base_url => 'https://localhost',
- :login_without_cas => false,
- :auto_create_users => false,
- :auto_update_attributes_on_login => false
- }, :partial => 'settings/settings'
+ settings :default => {
+ :enabled => false,
+ :cas_base_url => 'https://localhost',
+ :login_without_cas => false,
+ :auto_create_users => false,
+ :auto_update_attributes_on_login => false
+ }, :partial => 'settings/settings'
+ end
end
# Utility class to simplify plugin usage
class RedmineCas
class << self
+ def client_configured?
+ if client_config
+ !client_config[cas_base_url].blank?
+ end
+ end
+
def client_config
CASClient::Frameworks::Rails::Filter.config
end
@@ -76,26 +85,45 @@ def configure!
# Is CAS enabled, client configured and server available
def ready?
- get_setting(:enabled) && server_reachable_by_client?
+ get_setting(:enabled) && client_configured? && url_has_open_port?(client_config[:cas_base_url])
end
- # Check if server at configured url is alive
- def server_reachable_by_client?
- @server_available_for_url ||= {}
- if client_config
- if url = client_config[:cas_base_url]
- if @server_available_for_url[url]
- true
- else
- if (!HTTPClient.new.get_content(url).empty? rescue false)
- @server_available_for_url[url] = true
- else
- false
+ # Check if a host at provided url is reachable and has an open port
+ def url_has_open_port?(url, use_successful_results_cache = true)
+ begin
+ @successful_results_cache ||= {}
+ if use_successful_results_cache && @successful_results_cache[url]
+
+ # Successfully checked this host before
+ true
+ else
+
+ # Let's parse the url first
+ parsed_url = URI.parse(url)
+ begin
+
+ # Opening a socket can take too long, time out in magic 3 seconds
+ Timeout::timeout(3) do
+ begin
+ puts "checking #{parsed_url.host} port #{parsed_url.port} #{parsed_url.to_yaml}"
+ TCPSocket.new(parsed_url.host, parsed_url.port).close
+ @successful_results_cache[url] = true
+ rescue # Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEOUT
+
+ # Host not found, port not opened or other error
+ false
+ end
end
+ rescue Timeout::Error
+
+ # For us it's the same as host not reachable
+ false
end
- else
- false
end
+ rescue
+
+ # Unknown error
+ false
end
end
@@ -121,93 +149,97 @@ def user_attributes_by_session(session)
# This way we can work in development environment (where to_prepare is executed on every page reload)
# and production (executed once on first page load only).
# This way we're avoiding the problem where Rails reloads models but not plugins in development mode.
-ActionController::Dispatcher.to_prepare do
+if defined?(ActionController)
+
+ ActionController::Dispatcher.to_prepare do
- # We're watching for setting updates for the plugin.
- # After each change we want to reconfigure CAS client.
- Setting.class_eval do
- after_save do
- if name == 'plugin_redmine_cas'
- RedmineCas.configure!
+ # We're watching for setting updates for the plugin.
+ # After each change we want to reconfigure CAS client.
+ Setting.class_eval do
+ after_save do
+ if name == 'plugin_redmine_cas'
+ RedmineCas.configure!
+ end
end
end
- end
- # Let's (re)configure our plugin according to the current settings
- RedmineCas.configure!
+ # Let's (re)configure our plugin according to the current settings
+ RedmineCas.configure!
- AccountController.class_eval do
+ AccountController.class_eval do
- def login_with_cas
- if params[:username].blank? && params[:password].blank? && RedmineCas.ready?
- if session[:user_id]
- true
- else
- if CASClient::Frameworks::Rails::Filter.filter(self)
+ def login_with_cas
+ if params[:username].blank? && params[:password].blank? && RedmineCas.ready?
+ if session[:user_id]
+ true
+ else
+ if CASClient::Frameworks::Rails::Filter.filter(self)
- # User has been successfully authenticated with CAS
- user = User.find_or_initialize_by_login(session[:cas_user])
- unless user.new_record?
+ # User has been successfully authenticated with CAS
+ user = User.find_or_initialize_by_login(session[:cas_user])
+ unless user.new_record?
- # ...and also found in Redmine
- if user.active?
+ # ...and also found in Redmine
+ if user.active?
- # ...and user is active
- if RedmineCas.get_setting(:auto_update_attributes_on_login)
+ # ...and user is active
+ if RedmineCas.get_setting(:auto_update_attributes_on_login)
- # Plugin configured to update users from CAS extra user attributes
- unless user.update_attributes(RedmineCas.user_attributes_by_session(session))
- # TODO: error updating attributes on login from CAS. We can skip this for now.
+ # Plugin configured to update users from CAS extra user attributes
+ unless user.update_attributes(RedmineCas.user_attributes_by_session(session))
+ # TODO: error updating attributes on login from CAS. We can skip this for now.
+ end
end
+ successful_authentication(user)
+ else
+ account_pending
end
- successful_authentication(user)
else
- account_pending
- end
- else
- # ...user has been authenticated with CAS but not found in Redmine
- if RedmineCas.get_setting(:auto_create_users)
+ # ...user has been authenticated with CAS but not found in Redmine
+ if RedmineCas.get_setting(:auto_create_users)
- # Plugin config says to create user, let's try by getting as much as possible
- # from CAS extra user attributes. To add/remove extra attributes passed from CAS
- # server, please refer to your CAS server documentation.
- user.attributes = RedmineCas.user_attributes_by_session(session)
- user.status = User::STATUS_REGISTERED
+ # Plugin config says to create user, let's try by getting as much as possible
+ # from CAS extra user attributes. To add/remove extra attributes passed from CAS
+ # server, please refer to your CAS server documentation.
+ user.attributes = RedmineCas.user_attributes_by_session(session)
+ user.status = User::STATUS_REGISTERED
- register_automatically(user) do
- onthefly_creation_failed(user)
- end
- else
+ register_automatically(user) do
+ onthefly_creation_failed(user)
+ end
+ else
- # User auto-create disabled in plugin config
- flash[:error] = l(:cas_authenticated_user_not_found, session[:cas_user])
- redirect_to home_url
+ # User auto-create disabled in plugin config
+ flash[:error] = l(:cas_authenticated_user_not_found, session[:cas_user])
+ redirect_to home_url
+ end
end
- end
- else
+ else
- # Not authenticated with CAS, CASClient::Frameworks::Rails::Filter.filter(self) takes care of redirection
+ # Not authenticated with CAS, CASClient::Frameworks::Rails::Filter.filter(self) takes care of redirection
+ end
end
+ else
+ login_without_cas
end
- else
- login_without_cas
end
- end
- alias_method_chain :login, :cas
+ alias_method_chain :login, :cas
- def logout_with_cas
- if RedmineCas.ready?
- CASClient::Frameworks::Rails::Filter.logout(self, home_url)
- logout_user
- else
- logout_without_cas
+ def logout_with_cas
+ if RedmineCas.ready?
+ CASClient::Frameworks::Rails::Filter.logout(self, home_url)
+ logout_user
+ else
+ logout_without_cas
+ end
end
- end
- alias_method_chain :logout, :cas
+ alias_method_chain :logout, :cas
+ end
+
end
-end
+end

0 comments on commit da7cfcc

Please sign in to comment.