rack-casual 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,10 +1,16 @@
1
1
  Rack::Casual
2
2
  ============
3
3
 
4
- A very simple Rack authentication plugin using CAS or a token.
4
+ A simple Rack middleware that does authentication using CAS or a token.
5
5
  It kicks in whenever a 401 response is returned from the server.
6
6
 
7
- The plugin has only been tested using ActiveRecord and Rails 3.
7
+ Compability
8
+ ===========
9
+
10
+ * Ruby 1.8.7 and 1.9.2
11
+ * CAS 2.0 using rubycas-server
12
+ * Rails 3 and ActiveRecord 3
13
+ * Sinatra 1.0
8
14
 
9
15
 
10
16
  Installation
@@ -42,7 +42,7 @@ class User
42
42
  end
43
43
 
44
44
  def active?
45
- false
45
+ true
46
46
  end
47
47
 
48
48
  def save
@@ -5,4 +5,12 @@ class RackCasualGenerator < Rails::Generators::Base
5
5
  copy_file "initializer.rb", "config/initializers/rack-casual.rb"
6
6
  end
7
7
 
8
+ def print_usage
9
+ puts
10
+ puts "Remember to include the middleware in your application."
11
+ puts "You can put this into config/application.rb:"
12
+ puts " config.middleware.use 'Rack::Casual::Authentication'"
13
+ puts
14
+ end
15
+
8
16
  end
@@ -4,7 +4,7 @@
4
4
  Rack::Casual.setup do |config|
5
5
 
6
6
  # Base URL to your CAS server -- required
7
- config.base_url = 'http://localhost:8088'
7
+ config.cas_url = 'http://localhost:8088'
8
8
 
9
9
  # If you want users to authenticate using an authentication token,
10
10
  # set the auth_token_key to the name of the attribute in your user model.
@@ -14,7 +14,7 @@ Rack::Casual.setup do |config|
14
14
 
15
15
  # Name of the session key used to store the user-id
16
16
  # Default is "user", so you get session[:user]
17
- # config.session_key_user = "user"
17
+ # config.session_key = "user"
18
18
 
19
19
  # Rack::Casual can create the user automatically on successful login
20
20
  # Set this to false to disable this feature.
@@ -30,11 +30,6 @@ Rack::Casual.setup do |config|
30
30
  # This is the username attribute used by your User model.
31
31
  # config.username = "username"
32
32
 
33
- # Finding the user
34
- # You can set a custom scope that Rack::Casual should use when finding the user.
35
- # If you have a active scope, you can set this to :active.
36
- # config.authentication_scope = nil
37
-
38
33
  # Tracking
39
34
  # If you have last_login_at and/or last_login_ip attributes on your User model,
40
35
  # Rack::Casual can update these when user logs in.
data/lib/rack/casual.rb CHANGED
@@ -8,7 +8,10 @@ module Rack
8
8
  autoload :Authentication, 'rack/casual/authentication'
9
9
  autoload :Client, 'rack/casual/client'
10
10
  autoload :UserFactory, 'rack/casual/user_factory'
11
- autoload :Controller, 'rack/casual/controller'
11
+
12
+ if defined?(ActionController)
13
+ autoload :Controller, 'rack/casual/controller'
14
+ end
12
15
 
13
16
  # Default options
14
17
  defaults = {
@@ -41,74 +44,12 @@ module Rack
41
44
  self.send("#{key}=", value)
42
45
  end
43
46
 
44
- # # URI to CAS login
45
- # # Default is base_url/login
46
- # def self.login_url; @@login_url; end
47
- # def self.login_url=(login_url)
48
- #
49
- # mattr_accessor :login_url
50
- # @@login_url = nil
51
- #
52
- # # URI to CAS logout
53
- # # Default is base_url/logout
54
- # mattr_accessor :logout_url
55
- # @@logout_url = nil
56
- #
57
- # # URI to service validation
58
- # # Default is base_url/serviceValidate
59
- # mattr_accessor :validate_url
60
- # @@validate_url = nil
61
- #
62
- # # Name of authentication token to use in params
63
- # # Set to nil to disable token authentication
64
- # mattr_accessor :auth_token_key
65
- # @@auth_token_key = "auth_token"
66
- #
67
- # # Name of the ticket parameter used by CAS
68
- # mattr_accessor :ticket_param
69
- # @@ticket_param = "ticket"
70
- #
71
- # # Name of key to store user id
72
- # # Default is 'user' => session[:user]
73
- # mattr_accessor :session_key_user
74
- # @@session_key_user = "user"
75
- #
76
- # # Use this scope when finding users
77
- # mattr_accessor :authentication_scope
78
- # @@authentication_scope = nil
79
- #
80
- # # Set to true to auto-create users
81
- # mattr_accessor :create_user
82
- # @@create_user = true
83
- #
84
- # # Name of the User class
85
- # mattr_accessor :user_class
86
- # @@user_class = "User"
87
- #
88
- # # Username attribute on user
89
- # mattr_accessor :username
90
- # @@username = "username"
91
- #
92
- # # Update user with last_login_at and last_login_ip info
93
- # mattr_accessor :tracking_enabled
94
- # @@tracking_enabled = true
95
-
96
47
  # Setup Rack::Casual. Run rails generate rack_casual to create
97
48
  # a fresh initializer with all configuration values.
98
49
  def self.setup
99
50
  yield self
100
51
  end
101
52
 
102
- def self.cas_client
103
- @@cas_client ||= Client.new
104
- # @@cas_client ||= ::CASClient::Client.new(
105
- # :cas_base_url => @@base_url,
106
- # :login_url => @@login_url,
107
- # :logout_url => @@logout_url,
108
- # :validate_url => @@validate_url
109
- # )
110
- end
111
-
112
53
  end
113
54
 
114
55
  end
@@ -4,127 +4,127 @@ require 'nokogiri'
4
4
  require 'open-uri'
5
5
  require 'net/http'
6
6
  require 'net/https'
7
+ require 'yaml'
7
8
 
8
- # This is a über simple CAS client responsible for validating a ticket.
9
- class Rack::Casual::Client
10
- attr_accessor :username, :extra_attributes
9
+ # Simple CAS client responsible for validating a ticket.
10
+ module Rack
11
+ module Casual
11
12
 
12
- # Returns login url as string
13
- def self.login_url(service_url)
14
- new(service_url).login_url.to_s
15
- end
16
-
17
- # Creates a new object
18
- def initialize(service_url, ticket=nil)
19
- raise(ArgumentError, "Base URL must be configured") if Rack::Casual.cas_url.nil?
13
+ class Client
14
+ attr_accessor :username, :extra_attributes
15
+
16
+ # Creates a new object
17
+ def initialize(service_url, ticket=nil)
18
+ raise(ArgumentError, "Base URL must be configured") if Rack::Casual.cas_url.nil?
20
19
 
21
- @service_url = service_url
22
- @ticket = ticket
23
- @result = nil
24
- end
20
+ @service_url = service_url
21
+ @ticket = ticket
22
+ @result, @username, @extra_attributes = nil
23
+ end
24
+
25
+
26
+ # Helper that returns the CAS login url as string
27
+ def self.login_url(service_url)
28
+ cas_url(:login, :service => service_url).to_s
29
+ end
30
+
31
+ # Return url to CAS logout page
32
+ def self.logout_url(options={})
33
+ cas_url(:logout, options).to_s
34
+ end
25
35
 
26
- # Return the URL to the CAS login page
27
- def login_url
28
- cas_url(:login)
29
- end
36
+ # Return the URL to the CAS login page
37
+ def login_url
38
+ Client.cas_url(:login, :service => @service_url)
39
+ end
30
40
 
31
- # URL to the CAS ticket validation service
32
- def validation_url
33
- cas_url(:validate)
34
- end
41
+ # URL to the CAS ticket validation service
42
+ def validation_url
43
+ Client.cas_url(:validate, :ticket => @ticket, :service => @service_url)
44
+ end
35
45
 
36
- # Validate the ticket we got from CAS
37
- #
38
- # On ticket validation success:
39
- # <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
40
- # <cas:authenticationSuccess>
41
- # <cas:user>username</cas:user>
42
- # <cas:proxyGrantingTicket>PGTIOU-84678-8a9d...
43
- # </cas:proxyGrantingTicket>
44
- # </cas:authenticationSuccess>
45
- # </cas:serviceResponse>
46
- #
47
- # On ticket validation failure:
48
- # <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
49
- # <cas:authenticationFailure code="INVALID_TICKET">
50
- # Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized
51
- # </cas:authenticationFailure>
52
- # </cas:serviceResponse>
53
- #
54
- #
55
- def validate_ticket
56
- url = validation_url
57
- http = Net::HTTP.new(url.host, url.port)
58
- http.use_ssl = (url.scheme == "https")
46
+ # Validate the ticket we got from CAS
47
+ #
48
+ # On ticket validation success:
49
+ # <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
50
+ # <cas:authenticationSuccess>
51
+ # <cas:user>username</cas:user>
52
+ # <cas:proxyGrantingTicket>PGTIOU-84678-8a9d...
53
+ # </cas:proxyGrantingTicket>
54
+ # </cas:authenticationSuccess>
55
+ # </cas:serviceResponse>
56
+ #
57
+ # On ticket validation failure:
58
+ # <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
59
+ # <cas:authenticationFailure code="INVALID_TICKET">
60
+ # Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized
61
+ # </cas:authenticationFailure>
62
+ # </cas:serviceResponse>
63
+ #
64
+ #
65
+ def validate_ticket
66
+ url = validation_url
67
+ http = Net::HTTP.new(url.host, url.port)
68
+ http.use_ssl = (url.scheme == "https")
59
69
 
60
- result = Nokogiri.parse(http.get(url.request_uri).body)
70
+ body = http.get(url.request_uri).body
71
+ puts "Result: #{body}"
72
+ result = Nokogiri.parse(body)
61
73
 
62
- # set username and extra attributes
63
- find_username(result)
64
- find_attributes(result) if @username
74
+ # set username and extra attributes
75
+ find_username(result)
76
+ find_attributes(result) if @username
65
77
 
66
- !@username.nil?
67
- end
78
+ !@username.nil?
79
+ end
68
80
 
69
- def find_username(xml)
70
- @username = xml.search("//cas:authenticationSuccess //cas:user").first.text rescue nil
71
- end
81
+ def find_username(xml)
82
+ @username = xml.search("//cas:authenticationSuccess //cas:user").first.text rescue nil
83
+ end
72
84
 
73
- def find_attributes(xml)
74
- @extra_attributes = {}
75
- xml.search("//cas:authenticationSuccess/*").each do |el|
76
- # puts " * Attribute #{el.name} = #{el.content}"
77
- @extra_attributes[el.name] = el.content
78
- end
79
- end
85
+ def find_attributes(xml)
86
+ @extra_attributes = {}
87
+ xml.search("//cas:authenticationSuccess/*").each do |el|
88
+ puts " * Attribute #{el.name} = #{el.content.to_s}"
89
+ value = YAML::parse(el.content).value.first.value rescue nil
90
+ @extra_attributes[el.name] = value
91
+ end
92
+ end
80
93
 
81
- # For testing purposes only
82
- #
83
- # Fetch login ticket from the CAS login page
84
- # def acquire_login_ticket(service_url=nil)
85
- # Nokogiri.parse(open(login_url(service_url)).read).search('input[@name=lt]').first.attr('value') rescue nil
86
- # end
87
- #
88
- # def authenticate(username, password, ticket, service_url=nil)
89
- # ticket = acquire_login_ticket(service_url)
90
- # url = login_url(service_url)
91
- #
92
- # query = url.query ? url.query : ""
93
- # query += "&" + build_query(:username => username, :password => password, :lt => ticket, :service => service_url)
94
- #
95
- # req = Net::HTTP.new(url.host, url.port)
96
- # res = req.post url.path, query
97
- #
98
- # res.is_a?(Net::HTTPSuccess)
99
- # end
100
-
101
- #
102
- # Returns a CAS url
103
- # if action is :login or :validate, then the appropriate login and service-validation actions are used.
104
- # Otherwise the argument is used as the first action.
105
- #
106
- # Options is a hash that is appended to the url.
107
- #
108
- # Return value is a URI object.
109
- #
110
- # Examples:
111
- #
112
- # cas_url :login # => http://localhost/login
113
- # cas_url :validate, :ticket => "T123" # => http://localhost/serviceValidate?ticket=T123
114
- #
115
- def cas_url(action=nil, options = nil)
116
- url = Rack::Casual.cas_url.sub(/\/+$/, '')
94
+ #
95
+ # Returns a CAS url
96
+ # if action is :login or :validate, then the appropriate login and service-validation actions are used.
97
+ # Otherwise the argument is used as the first action.
98
+ #
99
+ # Options is a hash that is appended to the url.
100
+ #
101
+ # Return value is a URI object.
102
+ #
103
+ # Examples:
104
+ #
105
+ # cas_url :login # => http://localhost/login
106
+ # cas_url :validate, :ticket => "T123" # => http://localhost/serviceValidate?ticket=T123
107
+ #
108
+ def self.cas_url(action=nil, options = {})
109
+ url = Rack::Casual.cas_url.sub(/\/+$/, '')
117
110
 
118
- url << case action
119
- when :login then "/login"
120
- when :validate then "/serviceValidate"
121
- else
122
- action.to_s
123
- end
111
+ url << case action
112
+ when :login then "/login"
113
+ when :logout then "/logout"
114
+ when :validate then "/serviceValidate"
115
+ else
116
+ action.to_s
117
+ end
124
118
 
125
- url += "?service=#{@service_url}"
126
- url += "&ticket=#{@ticket}" if @ticket
127
- URI.parse(url)
128
- end
119
+ options = options.reject { |key,value| value.nil? }
120
+ if options.any?
121
+ url += "?" + options.map{|key,value| "#{key}=#{value}" }.join("&")
122
+ end
123
+
124
+ URI.parse(url)
125
+ end
129
126
 
130
- end
127
+ end
128
+
129
+ end
130
+ end
@@ -2,19 +2,32 @@
2
2
  module Rack
3
3
 
4
4
  module Casual
5
-
5
+
6
+ # Mixin module for ActionController
6
7
  module Controller
7
8
 
9
+ # Will send a 401 response to the user if user isn't logged in.
8
10
  def authenticate!
9
11
  authenticate_or_request_with_http_token unless logged_in?
10
12
  end
11
13
 
14
+ # Returns true if user is logged in
12
15
  def logged_in?
13
- !session[::Rack::Casual.session_key_user].nil?
16
+ !session[Casual.session_key].nil?
14
17
  end
15
18
 
19
+ # Returns the logged in user
16
20
  def current_user
17
- @current_user ||= ::Rack::Casual::UserFactory.authentication_scope.find(session[:user])
21
+ return @current_user if @current_user
22
+ @current_user = UserFactory.resource.find(session[Casual.session_key])
23
+
24
+ # If user is not active, unset session
25
+ if UserFactory.user_not_active(@current_user)
26
+ @current_user = nil
27
+ session[Casual.session_key] = nil
28
+ end
29
+
30
+ @current_user
18
31
  end
19
32
 
20
33
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-casual
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 1
9
- - 0
10
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - Gudleik Rasch
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 1
30
28
  segments:
31
29
  - 1
32
30
  - 4
@@ -42,7 +40,6 @@ dependencies:
42
40
  requirements:
43
41
  - - ~>
44
42
  - !ruby/object:Gem::Version
45
- hash: 62196427
46
43
  segments:
47
44
  - 2
48
45
  - 0
@@ -60,14 +57,13 @@ dependencies:
60
57
  requirements:
61
58
  - - ~>
62
59
  - !ruby/object:Gem::Version
63
- hash: 9
64
60
  segments:
65
61
  - 1
66
62
  - 3
67
63
  version: "1.3"
68
64
  type: :development
69
65
  version_requirements: *id003
70
- description: Rack middleware for authentication using CAS and/or tokens
66
+ description: Rack middleware for authentication using CAS and/or token
71
67
  email:
72
68
  - gudleik@gmail.com
73
69
  executables: []
@@ -103,7 +99,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
99
  requirements:
104
100
  - - ">="
105
101
  - !ruby/object:Gem::Version
106
- hash: 3
107
102
  segments:
108
103
  - 0
109
104
  version: "0"
@@ -112,7 +107,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
107
  requirements:
113
108
  - - ">="
114
109
  - !ruby/object:Gem::Version
115
- hash: 21
116
110
  segments:
117
111
  - 1
118
112
  - 3
@@ -124,6 +118,6 @@ rubyforge_project:
124
118
  rubygems_version: 1.3.7
125
119
  signing_key:
126
120
  specification_version: 3
127
- summary: CAS and token authentication using Rack
121
+ summary: Rack middleware for authentication using CAS and/or token
128
122
  test_files: []
129
123