rubycas-client 2.2.1 → 2.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +13 -0
- data/Gemfile.lock +30 -0
- data/History.txt +21 -0
- data/README.rdoc +24 -20
- data/Rakefile +43 -54
- data/VERSION +1 -0
- data/examples/rails/README +16 -0
- data/examples/rails/app/controllers/advanced_example_controller.rb +31 -0
- data/examples/rails/app/controllers/application.rb +2 -0
- data/examples/rails/app/controllers/simple_example_controller.rb +16 -0
- data/examples/rails/app/views/advanced_example/index.html.erb +13 -0
- data/examples/rails/app/views/advanced_example/my_account.html.erb +11 -0
- data/examples/rails/app/views/simple_example/index.html.erb +6 -0
- data/examples/rails/config/boot.rb +109 -0
- data/examples/rails/config/environment.rb +39 -0
- data/examples/rails/config/environments/development.rb +17 -0
- data/examples/rails/config/environments/production.rb +22 -0
- data/examples/rails/config/environments/test.rb +22 -0
- data/examples/rails/config/initializers/inflections.rb +10 -0
- data/examples/rails/config/initializers/mime_types.rb +5 -0
- data/examples/rails/config/initializers/new_rails_defaults.rb +17 -0
- data/examples/rails/config/routes.rb +4 -0
- data/examples/rails/log/development.log +946 -0
- data/examples/rails/log/production.log +0 -0
- data/examples/rails/log/server.log +0 -0
- data/examples/rails/log/test.log +0 -0
- data/examples/rails/script/about +4 -0
- data/examples/rails/script/console +3 -0
- data/examples/rails/script/server +3 -0
- data/lib/casclient/client.rb +49 -36
- data/lib/casclient/frameworks/rails/cas_proxy_callback_controller.rb +5 -39
- data/lib/casclient/frameworks/rails/filter.rb +86 -113
- data/lib/casclient/responses.rb +29 -16
- data/lib/casclient/tickets/storage/active_record_ticket_store.rb +67 -0
- data/lib/casclient/tickets/storage.rb +167 -0
- data/lib/casclient/tickets.rb +3 -3
- data/lib/casclient.rb +3 -2
- data/lib/rubycas-client.rb +1 -5
- data/rails_generators/active_record_ticket_store/USAGE +9 -0
- data/rails_generators/active_record_ticket_store/active_record_ticket_store_generator.rb +29 -0
- data/rails_generators/active_record_ticket_store/templates/README +1 -0
- data/rails_generators/active_record_ticket_store/templates/migration.rb +24 -0
- data/rubycas-client.gemspec +103 -0
- data/test/teststrap.rb +10 -0
- data/test/units/casclient/frameworks/rails/filter_test.rb +184 -0
- metadata +148 -47
- data/Manifest.txt +0 -23
- data/examples/merb/README.textile +0 -12
- data/examples/merb/Rakefile +0 -35
- data/examples/merb/merb.thor +0 -2020
- data/examples/merb/merb_auth_cas.rb +0 -67
- data/examples/merb/spec/spec_helper.rb +0 -24
- data/init.rb +0 -6
- data/lib/casclient/frameworks/merb/filter.rb +0 -105
- data/lib/casclient/frameworks/merb/strategy.rb +0 -110
- data/lib/casclient/version.rb +0 -9
- data/setup.rb +0 -1585
data/lib/casclient/responses.rb
CHANGED
@@ -31,15 +31,14 @@ module CASClient
|
|
31
31
|
|
32
32
|
attr_reader :protocol, :user, :pgt_iou, :proxies, :extra_attributes
|
33
33
|
|
34
|
-
def initialize(raw_text)
|
35
|
-
parse(raw_text)
|
34
|
+
def initialize(raw_text, options={})
|
35
|
+
parse(raw_text, options)
|
36
36
|
end
|
37
37
|
|
38
|
-
def parse(raw_text)
|
38
|
+
def parse(raw_text, options)
|
39
39
|
raise BadResponseException,
|
40
40
|
"CAS response is empty/blank." if raw_text.blank?
|
41
41
|
@parse_datetime = Time.now
|
42
|
-
|
43
42
|
if raw_text =~ /^(yes|no)\n(.*?)\n$/m
|
44
43
|
@protocol = 1.0
|
45
44
|
@valid = $~[1] == 'yes'
|
@@ -53,7 +52,8 @@ module CASClient
|
|
53
52
|
@protocol = 2.0
|
54
53
|
|
55
54
|
if is_success?
|
56
|
-
|
55
|
+
cas_user = @xml.elements["cas:user"]
|
56
|
+
@user = cas_user.text.strip if cas_user
|
57
57
|
@pgt_iou = @xml.elements["cas:proxyGrantingTicket"].text.strip if @xml.elements["cas:proxyGrantingTicket"]
|
58
58
|
|
59
59
|
proxy_els = @xml.elements.to_a('//cas:authenticationSuccess/cas:proxies/cas:proxy')
|
@@ -65,16 +65,32 @@ module CASClient
|
|
65
65
|
end
|
66
66
|
|
67
67
|
@extra_attributes = {}
|
68
|
-
@xml.elements.to_a('//cas:authenticationSuccess/*').each do |el|
|
69
|
-
|
68
|
+
@xml.elements.to_a('//cas:authenticationSuccess/cas:attributes/* | //cas:authenticationSuccess/*[local-name() != \'proxies\' and local-name() != \'proxyGrantingTicket\' and local-name() != \'user\' and local-name() != \'attributes\']').each do |el|
|
69
|
+
# generating the hash requires prefixes to be defined, so add all of the namespaces
|
70
|
+
el.namespaces.each {|k,v| el.add_namespace(k,v)}
|
71
|
+
@extra_attributes.merge!(Hash.from_xml(el.to_s))
|
70
72
|
end
|
71
73
|
|
72
74
|
# unserialize extra attributes
|
73
75
|
@extra_attributes.each do |k, v|
|
74
76
|
if v.blank?
|
75
77
|
@extra_attributes[k] = nil
|
76
|
-
|
77
|
-
|
78
|
+
elsif !options[:encode_extra_attributes_as]
|
79
|
+
begin
|
80
|
+
@extra_attributes[k] = YAML.load(v)
|
81
|
+
rescue ArgumentError
|
82
|
+
raise ArgumentError, "Did not find :encode_extra_attributes_as config parameter, hence default encoding scheme is YAML but CAS response recieved in encoded differently "
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if options[:encode_extra_attributes_as] == :json
|
86
|
+
begin
|
87
|
+
@extra_attributes[k] = JSON.parse(v)
|
88
|
+
rescue JSON::ParserError
|
89
|
+
@extra_attributes[k] = YAML.load(v)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
@extra_attributes[k] = YAML.load(v)
|
93
|
+
end
|
78
94
|
end
|
79
95
|
end
|
80
96
|
elsif is_failure?
|
@@ -84,9 +100,8 @@ module CASClient
|
|
84
100
|
# this should never happen, since the response should already have been recognized as invalid
|
85
101
|
raise BadResponseException, "BAD CAS RESPONSE:\n#{raw_text.inspect}\n\nXML DOC:\n#{doc.inspect}"
|
86
102
|
end
|
87
|
-
|
88
103
|
end
|
89
|
-
|
104
|
+
|
90
105
|
def is_success?
|
91
106
|
(instance_variable_defined?(:@valid) && @valid) || (protocol > 1.0 && xml.name == "authenticationSuccess")
|
92
107
|
end
|
@@ -103,7 +118,7 @@ module CASClient
|
|
103
118
|
|
104
119
|
attr_reader :proxy_ticket
|
105
120
|
|
106
|
-
def initialize(raw_text)
|
121
|
+
def initialize(raw_text, options={})
|
107
122
|
parse(raw_text)
|
108
123
|
end
|
109
124
|
|
@@ -141,7 +156,7 @@ module CASClient
|
|
141
156
|
attr_reader :tgt, :ticket, :service_redirect_url
|
142
157
|
attr_reader :failure_message
|
143
158
|
|
144
|
-
def initialize(http_response = nil)
|
159
|
+
def initialize(http_response = nil, options={})
|
145
160
|
parse_http_response(http_response) if http_response
|
146
161
|
end
|
147
162
|
|
@@ -160,9 +175,7 @@ module CASClient
|
|
160
175
|
@ticket = $~[1]
|
161
176
|
end
|
162
177
|
|
163
|
-
if (http_response.kind_of?(Net::HTTPSuccess) || http_response.kind_of?(Net::HTTPFound)) && @ticket.present?
|
164
|
-
log.info("Login was successful for ticket: #{@ticket.inspect}.")
|
165
|
-
else
|
178
|
+
if not ((http_response.kind_of?(Net::HTTPSuccess) || http_response.kind_of?(Net::HTTPFound)) && @ticket.present?)
|
166
179
|
@failure = true
|
167
180
|
# Try to extract the error message -- this only works with RubyCAS-Server.
|
168
181
|
# For other servers we just return the entire response body (i.e. the whole error page).
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module CASClient
|
2
|
+
module Tickets
|
3
|
+
module Storage
|
4
|
+
|
5
|
+
# A Ticket Store that keeps it's ticket in database tables using ActiveRecord.
|
6
|
+
#
|
7
|
+
# Services Tickets are stored in an extra column add to the ActiveRecord sessions table.
|
8
|
+
# Proxy Granting Tickets and their IOUs are stored in the cas_pgtious table.
|
9
|
+
#
|
10
|
+
# This ticket store takes the following config parameters
|
11
|
+
# :pgtious_table_name - the name of the table
|
12
|
+
class ActiveRecordTicketStore < AbstractTicketStore
|
13
|
+
|
14
|
+
def initialize(config={})
|
15
|
+
config ||= {}
|
16
|
+
if config[:pgtious_table_name]
|
17
|
+
CasPgtiou.set_table_name = config[:pgtious_table_name]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def store_service_session_lookup(st, controller)
|
22
|
+
#get the session from the rack env using ActiveRecord::SessionStore::SESSION_RECORD_KEY = 'rack.session.record'
|
23
|
+
|
24
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
25
|
+
session = controller.request.env[ActiveRecord::SessionStore::SESSION_RECORD_KEY]
|
26
|
+
session.service_ticket = st
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_session_for_service_ticket(st)
|
30
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
31
|
+
session = ActiveRecord::SessionStore::Session.find_by_service_ticket(st)
|
32
|
+
session_id = session ? session.session_id : nil
|
33
|
+
[session_id, session]
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup_service_session_lookup(st)
|
37
|
+
#no cleanup needed for this ticket store
|
38
|
+
end
|
39
|
+
|
40
|
+
def save_pgt_iou(pgt_iou, pgt)
|
41
|
+
pgtiou = CasPgtiou.create(:pgt_iou => pgt_iou, :pgt_id => pgt)
|
42
|
+
end
|
43
|
+
|
44
|
+
def retrieve_pgt(pgt_iou)
|
45
|
+
raise CASException, "No pgt_iou specified. Cannot retrieve the pgt." unless pgt_iou
|
46
|
+
|
47
|
+
pgtiou = CasPgtiou.find_by_pgt_iou(pgt_iou)
|
48
|
+
pgt = pgtiou.pgt_id
|
49
|
+
|
50
|
+
raise CASException, "Invalid pgt_iou specified. Perhaps this pgt has already been retrieved?" unless pgt
|
51
|
+
|
52
|
+
pgtiou.destroy
|
53
|
+
|
54
|
+
pgt
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class CasPgtiou < ActiveRecord::Base
|
61
|
+
#t.string :pgt_iou, :null => false
|
62
|
+
#t.string :pgt_id, :null => false
|
63
|
+
#t.timestamps
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module CASClient
|
2
|
+
module Tickets
|
3
|
+
module Storage
|
4
|
+
class AbstractTicketStore
|
5
|
+
|
6
|
+
attr_accessor :log
|
7
|
+
@log = CASClient::LoggerWrapper.new
|
8
|
+
|
9
|
+
def process_single_sign_out(si)
|
10
|
+
|
11
|
+
session_id, session = get_session_for_service_ticket(si)
|
12
|
+
if session
|
13
|
+
session.destroy
|
14
|
+
log.debug("Destroyed #{session.inspect} for session #{session_id.inspect} corresponding to service ticket #{si.inspect}.")
|
15
|
+
else
|
16
|
+
log.debug("Data for session #{session_id.inspect} was not found. It may have already been cleared by a local CAS logout request.")
|
17
|
+
end
|
18
|
+
|
19
|
+
if session_id
|
20
|
+
log.info("Single-sign-out for service ticket #{session_id.inspect} completed successfuly.")
|
21
|
+
else
|
22
|
+
log.debug("No session id found for CAS ticket #{si}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_session_for_service_ticket(st)
|
27
|
+
session_id = read_service_session_lookup(si)
|
28
|
+
if session_id
|
29
|
+
session = ActiveRecord::SessionStore::Session.find_by_session_id(session_id)
|
30
|
+
else
|
31
|
+
log.warn("Couldn't destroy session with SessionIndex #{si} because no corresponding session id could be looked up.")
|
32
|
+
end
|
33
|
+
[session_id, session]
|
34
|
+
end
|
35
|
+
|
36
|
+
def store_service_session_lookup(st, controller)
|
37
|
+
raise 'Implement this in a subclass!'
|
38
|
+
end
|
39
|
+
|
40
|
+
def cleanup_service_session_lookup(st)
|
41
|
+
raise 'Implement this in a subclass!'
|
42
|
+
end
|
43
|
+
|
44
|
+
def save_pgt_iou(pgt_iou, pgt)
|
45
|
+
raise 'Implement this in a subclass!'
|
46
|
+
end
|
47
|
+
|
48
|
+
def retrieve_pgt(pgt_iou)
|
49
|
+
raise 'Implement this in a subclass!'
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def read_service_session_lookup(st)
|
54
|
+
raise 'Implement this in a subclass!'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# A Ticket Store that keeps it's tickets in a directory on the local filesystem.
|
59
|
+
# Service tickets are stored under tmp/sessions by default
|
60
|
+
# and Proxy Granting Tickets and their IOUs are stored in tmp/cas_pgt.pstore
|
61
|
+
# This Ticket Store works fine for small sites but will most likely have
|
62
|
+
# concurrency problems under heavy load. It also requires that all your
|
63
|
+
# worker processes have access to a shared file system.
|
64
|
+
#
|
65
|
+
# This ticket store takes the following config parameters
|
66
|
+
# :storage_dir - The directory to store data in. Defaults to RAILS_ROOT/tmp
|
67
|
+
# :service_session_lookup_dir - The directory to store Service Ticket/Session ID files in. Defaults to :storage_dir/sessions
|
68
|
+
# :pgt_store_path - The location to store the pgt PStore file. Defaults to :storage_dir/cas_pgt.pstore
|
69
|
+
class LocalDirTicketStore < AbstractTicketStore
|
70
|
+
require 'pstore'
|
71
|
+
|
72
|
+
DEFAULT_TMP_DIR = defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/tmp" : "#{Dir.pwd}/tmp"
|
73
|
+
|
74
|
+
def initialize(config={})
|
75
|
+
config ||= {}
|
76
|
+
@tmp_dir = config[:storage_dir] || DEFAULT_TMP_DIR
|
77
|
+
@service_session_lookup_dir = config[:service_session_lookup_dir] || "#{@tmp_dir}/sessions"
|
78
|
+
@pgt_store_path = config[:pgt_store_path] || "#{@tmp_dir}/cas_pgt.pstore"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Creates a file in tmp/sessions linking a SessionTicket
|
82
|
+
# with the local Rails session id. The file is named
|
83
|
+
# cas_sess.<session ticket> and its text contents is the corresponding
|
84
|
+
# Rails session id.
|
85
|
+
# Returns the filename of the lookup file created.
|
86
|
+
def store_service_session_lookup(st, controller)
|
87
|
+
raise CASException, "No service_ticket specified." unless st
|
88
|
+
raise CASException, "No controller specified." unless controller
|
89
|
+
|
90
|
+
sid = controller.request.session_options[:id] || controller.session.session_id
|
91
|
+
|
92
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
93
|
+
f = File.new(filename_of_service_session_lookup(st), 'w')
|
94
|
+
f.write(sid)
|
95
|
+
f.close
|
96
|
+
return f.path
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the local Rails session ID corresponding to the given
|
100
|
+
# ServiceTicket. This is done by reading the contents of the
|
101
|
+
# cas_sess.<session ticket> file created in a prior call to
|
102
|
+
# #store_service_session_lookup.
|
103
|
+
def read_service_session_lookup(st)
|
104
|
+
raise CASException, "No service_ticket specified." unless st
|
105
|
+
|
106
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
107
|
+
ssl_filename = filename_of_service_session_lookup(st)
|
108
|
+
return File.exists?(ssl_filename) && IO.read(ssl_filename)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Removes a stored relationship between a ServiceTicket and a local
|
112
|
+
# Rails session id. This should be called when the session is being
|
113
|
+
# closed.
|
114
|
+
#
|
115
|
+
# See #store_service_session_lookup.
|
116
|
+
def cleanup_service_session_lookup(st)
|
117
|
+
raise CASException, "No service_ticket specified." unless st
|
118
|
+
|
119
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
120
|
+
ssl_filename = filename_of_service_session_lookup(st)
|
121
|
+
File.delete(ssl_filename) if File.exists?(ssl_filename)
|
122
|
+
end
|
123
|
+
|
124
|
+
def save_pgt_iou(pgt_iou, pgt)
|
125
|
+
# TODO: pstore contents should probably be encrypted...
|
126
|
+
pstore = open_pstore
|
127
|
+
|
128
|
+
pstore.transaction do
|
129
|
+
pstore[pgt_iou] = pgt
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def retrieve_pgt(pgt_iou)
|
134
|
+
raise CASException, "No pgt_iou specified. Cannot retrieve the pgt." unless pgt_iou
|
135
|
+
|
136
|
+
pstore = open_pstore
|
137
|
+
|
138
|
+
pgt = nil
|
139
|
+
pstore.transaction do
|
140
|
+
pgt = pstore[pgt_iou]
|
141
|
+
end
|
142
|
+
|
143
|
+
raise CASException, "Invalid pgt_iou specified. Perhaps this pgt has already been retrieved?" unless pgt
|
144
|
+
|
145
|
+
# TODO: need to periodically clean the storage, otherwise it will just keep growing
|
146
|
+
pstore.transaction do
|
147
|
+
pstore.delete pgt_iou
|
148
|
+
end
|
149
|
+
|
150
|
+
pgt
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# Returns the path and filename of the service session lookup file.
|
156
|
+
def filename_of_service_session_lookup(st)
|
157
|
+
st = st.ticket if st.kind_of? ServiceTicket
|
158
|
+
return "#{@service_session_lookup_dir}/cas_sess.#{st}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def open_pstore
|
162
|
+
PStore.new(@pgt_store_path)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/casclient/tickets.rb
CHANGED
@@ -2,7 +2,7 @@ module CASClient
|
|
2
2
|
# Represents a CAS service ticket.
|
3
3
|
class ServiceTicket
|
4
4
|
attr_reader :ticket, :service, :renew
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :user, :extra_attributes, :pgt_iou, :success, :failure_code, :failure_message
|
6
6
|
|
7
7
|
def initialize(ticket, service, renew = false)
|
8
8
|
@ticket = ticket
|
@@ -11,11 +11,11 @@ module CASClient
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def is_valid?
|
14
|
-
|
14
|
+
success
|
15
15
|
end
|
16
16
|
|
17
17
|
def has_been_validated?
|
18
|
-
not
|
18
|
+
not user.nil?
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/lib/casclient.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'cgi'
|
3
|
+
require 'logger'
|
3
4
|
require 'net/https'
|
4
5
|
require 'rexml/document'
|
5
6
|
|
@@ -65,7 +66,7 @@ end
|
|
65
66
|
require 'casclient/tickets'
|
66
67
|
require 'casclient/responses'
|
67
68
|
require 'casclient/client'
|
68
|
-
require 'casclient/
|
69
|
+
require 'casclient/tickets/storage'
|
69
70
|
|
70
71
|
# Detect legacy configuration and show appropriate error message
|
71
72
|
module CAS
|
@@ -86,4 +87,4 @@ module CAS
|
|
86
87
|
end
|
87
88
|
end
|
88
89
|
end
|
89
|
-
end
|
90
|
+
end
|
data/lib/rubycas-client.rb
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
Description:
|
2
|
+
Create a migration to add the service_ticket column to the sessions
|
3
|
+
table and create the cas_pgtious table for proxy ticket storage.
|
4
|
+
Pass the migration name as an optional parameter. The migration name
|
5
|
+
defaults to CreateActiveRecordTicketStore.
|
6
|
+
|
7
|
+
Requirements:
|
8
|
+
You need to already have created the ActiveRecord::SessionStore sessions
|
9
|
+
table.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class ActiveRecordTicketStoreGenerator < Rails::Generator::NamedBase
|
2
|
+
|
3
|
+
def initialize(runtime_args, runtime_options = {})
|
4
|
+
runtime_args << 'create_active_record_ticket_store' if runtime_args.empty?
|
5
|
+
super
|
6
|
+
end
|
7
|
+
|
8
|
+
def manifest
|
9
|
+
record do |m|
|
10
|
+
m.migration_template 'migration.rb', 'db/migrate',
|
11
|
+
:assigns => { :session_table_name => default_session_table_name, :pgtiou_table_name => default_pgtiou_table_name }
|
12
|
+
m.readme "README"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def banner
|
18
|
+
"Usage: #{$0} #{spec.name} [CreateActiveRecordTicketStore] [options]"
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_session_table_name
|
22
|
+
ActiveRecord::Base.pluralize_table_names ? 'session'.pluralize : 'session'
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_pgtiou_table_name
|
26
|
+
ActiveRecord::Base.pluralize_table_names ? 'cas_pgtiou'.pluralize : 'cas_pgtiou'
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
You need to make sure you have already created the sessions table for the ActiveRecord::SessionStore
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :<%= session_table_name %>, :service_ticket, :string
|
4
|
+
|
5
|
+
add_index :<%= session_table_name %>, :service_ticket
|
6
|
+
|
7
|
+
create_table :<%= pgtiou_table_name %> do |t|
|
8
|
+
t.string :pgt_iou, :null => false
|
9
|
+
t.string :pgt_id, :null => false
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :<%= pgtiou_table_name %>, :pgt_iou, :unique => true
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
drop_table :<%= pgtiou_table_name %>
|
18
|
+
|
19
|
+
remove_index :<%= session_table_name %>, :service_ticket
|
20
|
+
|
21
|
+
remove_column :<%= session_table_name %>, :service_ticket
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|