rubycas-client 2.2.1 → 2.3.0.rc1
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/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
|
+
|