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 +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
|
|