rack-casual 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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