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 +8 -2
- data/examples/sinatra_app.rb +1 -1
- data/lib/generators/rack_casual_generator.rb +8 -0
- data/lib/generators/templates/initializer.rb +2 -7
- data/lib/rack/casual.rb +4 -63
- data/lib/rack/casual/client.rb +109 -109
- data/lib/rack/casual/controller.rb +16 -3
- metadata +4 -10
data/README.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
Rack::Casual
|
2
2
|
============
|
3
3
|
|
4
|
-
A
|
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
|
-
|
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
|
data/examples/sinatra_app.rb
CHANGED
@@ -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.
|
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.
|
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
|
-
|
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
|
data/lib/rack/casual/client.rb
CHANGED
@@ -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
|
-
#
|
9
|
-
|
10
|
-
|
9
|
+
# Simple CAS client responsible for validating a ticket.
|
10
|
+
module Rack
|
11
|
+
module Casual
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
70
|
+
body = http.get(url.request_uri).body
|
71
|
+
puts "Result: #{body}"
|
72
|
+
result = Nokogiri.parse(body)
|
61
73
|
|
62
|
-
|
63
|
-
|
64
|
-
|
74
|
+
# set username and extra attributes
|
75
|
+
find_username(result)
|
76
|
+
find_attributes(result) if @username
|
65
77
|
|
66
|
-
|
67
|
-
|
78
|
+
!@username.nil?
|
79
|
+
end
|
68
80
|
|
69
|
-
|
70
|
-
|
71
|
-
|
81
|
+
def find_username(xml)
|
82
|
+
@username = xml.search("//cas:authenticationSuccess //cas:user").first.text rescue nil
|
83
|
+
end
|
72
84
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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[
|
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
|
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
|
-
-
|
10
|
-
version: 0.1.
|
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
|
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:
|
121
|
+
summary: Rack middleware for authentication using CAS and/or token
|
128
122
|
test_files: []
|
129
123
|
|