rubycas-server 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +3 -0
- data/LICENSE.txt +339 -0
- data/Manifest.txt +32 -0
- data/README.txt +27 -0
- data/Rakefile +59 -0
- data/bin/rubycas-server +8 -0
- data/config.example.yml +197 -0
- data/lib/casserver.rb +152 -0
- data/lib/casserver/authenticators/active_directory_ldap.rb +8 -0
- data/lib/casserver/authenticators/base.rb +22 -0
- data/lib/casserver/authenticators/ldap.rb +40 -0
- data/lib/casserver/authenticators/sql.rb +37 -0
- data/lib/casserver/authenticators/test.rb +8 -0
- data/lib/casserver/cas.rb +224 -0
- data/lib/casserver/conf.rb +78 -0
- data/lib/casserver/controllers.rb +253 -0
- data/lib/casserver/models.rb +109 -0
- data/lib/casserver/utils.rb +33 -0
- data/lib/casserver/version.rb +9 -0
- data/lib/casserver/views.rb +185 -0
- data/lib/themes/cas.css +112 -0
- data/lib/themes/ok.png +0 -0
- data/lib/themes/simple/bg.png +0 -0
- data/lib/themes/simple/login_box_bg.png +0 -0
- data/lib/themes/simple/logo.png +0 -0
- data/lib/themes/simple/theme.css +28 -0
- data/lib/themes/urbacon/bg.png +0 -0
- data/lib/themes/urbacon/login_box_bg.png +0 -0
- data/lib/themes/urbacon/logo.png +0 -0
- data/lib/themes/urbacon/theme.css +33 -0
- data/lib/themes/warning.png +0 -0
- data/setup.rb +1585 -0
- data/test/test_casserver.rb +150 -0
- metadata +103 -0
data/bin/rubycas-server
ADDED
data/config.example.yml
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# IMPORTANT NOTE ABOUT YAML CONFIGURATION FILES
|
2
|
+
# ---> Be sure to use spaces instead of tabs for indentation. Yaml is white-space sensitive!
|
3
|
+
|
4
|
+
##### SERVER ########################################################################
|
5
|
+
|
6
|
+
# Under what environment are you running the CAS server? The following methods
|
7
|
+
# are currently supported:
|
8
|
+
#
|
9
|
+
# webrick -- run as a stand-alone webrick server; this is the default method
|
10
|
+
# mongrel -- run as a stand-alone mongrel server; fast, but you'll need to install
|
11
|
+
# mongrel and run it behind an https reverse proxy like Pound or Apache 2.2's mod_proxy)
|
12
|
+
# cgi -- slow, but simple to set up if you're already familliar with deploying CGI scripts
|
13
|
+
# fastcgi -- see http://www.fastcgi.com (e.g. under Apache you can use this with mod_fastcgi)
|
14
|
+
#
|
15
|
+
# The cgi and fastcgi methods have not been thoroughly tested!
|
16
|
+
# Please report any problems to the authors.
|
17
|
+
#
|
18
|
+
# IMPORTANT: If you use mongrel, you will need to run the server behind a reverse proxy
|
19
|
+
# (Pound, Apache 2.2 with mod_proxy, etc.) since mongrel does not support SSL/HTTPS.
|
20
|
+
# See the RubyCAS-Server install docs for more info. Also, mongrel requries
|
21
|
+
# Camping 1.5.180 which as of writing is only available via SVN. You can install
|
22
|
+
# this by running `gem install camping --source code.whytheluckystiff.net`
|
23
|
+
|
24
|
+
### webrick example
|
25
|
+
|
26
|
+
server: webrick
|
27
|
+
port: 443
|
28
|
+
ssl_cert: /path/to/your/ssl.pem
|
29
|
+
# ssl_key: /path/to/your/private_key.pem <-- if private key is separate from cert
|
30
|
+
|
31
|
+
### mongrel example (you will need to run this behind an https reverse proxy,
|
32
|
+
### since mongrel doesn't support SSL on its own)
|
33
|
+
|
34
|
+
#server: mongrel
|
35
|
+
#port: 110011
|
36
|
+
|
37
|
+
### cgi example (you'll need to serve this via an SSL-capable server like Apache)
|
38
|
+
|
39
|
+
#server: cgi
|
40
|
+
|
41
|
+
### fastcgi example (you'll need to serve this via an SSL-capable server like Apache)
|
42
|
+
|
43
|
+
#server: fastcgi
|
44
|
+
|
45
|
+
|
46
|
+
##### DATABASE #######################################################################
|
47
|
+
|
48
|
+
# Set up the database connection. Make sure that this database is secure!
|
49
|
+
#
|
50
|
+
# By default, we use sqlite3 since it works without any extra configuration.
|
51
|
+
# You can also use MySQL, PostgreSQL, MSSQL, or anything else supported by ActiveRecord.
|
52
|
+
#
|
53
|
+
# For example, with MySQL, your config wold be something like:
|
54
|
+
#
|
55
|
+
#database:
|
56
|
+
# adapter: mysql
|
57
|
+
# database: casserver
|
58
|
+
# user: root
|
59
|
+
# password:
|
60
|
+
# server: localhost
|
61
|
+
#
|
62
|
+
|
63
|
+
database:
|
64
|
+
adapter: sqlite3
|
65
|
+
dbfile: /var/lib/casserver.db
|
66
|
+
|
67
|
+
|
68
|
+
##### AUTHENTICATION #################################################################
|
69
|
+
|
70
|
+
# Configure how username/passwords are validated.
|
71
|
+
#
|
72
|
+
# !!! YOU MUST CONFIGURE ONE (AND ONLY ONE) OF THESE AUTHENTICATION METHODS !!!
|
73
|
+
#
|
74
|
+
# Currently there are three built-in methods for authentication:
|
75
|
+
# SQL, ActiveDirectory, and LDAP. If none of these work for you, it is relatively
|
76
|
+
# easy to write your own custom Authenticator class.
|
77
|
+
#
|
78
|
+
# ==> SQL Authentication:
|
79
|
+
# The simplest method is to validate against a SQL database. This assumes
|
80
|
+
# that all of your users are stored in a table that has a 'username' column
|
81
|
+
# and a 'password' column. When the user logs in, CAS conects to this database
|
82
|
+
# and look for a matching username/password in the users table. If a matching
|
83
|
+
# username and password is found, authentication is successful.
|
84
|
+
#
|
85
|
+
# Example:
|
86
|
+
#
|
87
|
+
#authenticator:
|
88
|
+
# class: CASServer::Authenticators::SQL
|
89
|
+
# database:
|
90
|
+
# adapter: mysql
|
91
|
+
# database: some_database_with_users_table
|
92
|
+
# user: root
|
93
|
+
# password:
|
94
|
+
# server: localhost
|
95
|
+
# user_table: user
|
96
|
+
# username_column: username
|
97
|
+
# password_column: password
|
98
|
+
#
|
99
|
+
#
|
100
|
+
# ==> ActiveDirectory Authentication:
|
101
|
+
# This method authenticates against Microsoft's ActiveDirectory using LDAP.
|
102
|
+
# You must enter your ActiveDirectory server, and base DN. The port number
|
103
|
+
# and LDAP filter are optional. You must also enter a username and password
|
104
|
+
# for an "authenticator" user. The authenticator users this account to
|
105
|
+
# log in to the ActiveDirectory server and search LDAP. This does not have
|
106
|
+
# to be an administrative account; it only has to be able to search for other
|
107
|
+
# users.
|
108
|
+
#
|
109
|
+
# Example:
|
110
|
+
#
|
111
|
+
#authenticator:
|
112
|
+
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
113
|
+
# ldap:
|
114
|
+
# server: ad.example.net
|
115
|
+
# port: 389
|
116
|
+
# base: dc=example,dc=net
|
117
|
+
# filter: (objectClass=person)
|
118
|
+
# auth_user: authenticator
|
119
|
+
# auth_password: itsasecret
|
120
|
+
#
|
121
|
+
#
|
122
|
+
# ==> LDAP Authentication:
|
123
|
+
# This is a more general version of the ActiveDirectory authenticator.
|
124
|
+
# The configuration is similar, except you don't need an authenticator
|
125
|
+
# username or password. Note that this authenticator hasn't been widely
|
126
|
+
# tested, so it is not guaranteed to work.
|
127
|
+
#
|
128
|
+
#authenticator:
|
129
|
+
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
130
|
+
# ldap:
|
131
|
+
# server: ad.example.net
|
132
|
+
# port: 389
|
133
|
+
# base: dc=example,dc=net
|
134
|
+
# filter: (objectClass=person)
|
135
|
+
#
|
136
|
+
#
|
137
|
+
# ==> Custom Authentication:
|
138
|
+
# It should be relatively easy to write your own Authenticator class. Have a look
|
139
|
+
# at the built-in authenticators in the casserver/authenticators directory. Your
|
140
|
+
# authenticator should extend the CASServer::Authenticators::Base class and must
|
141
|
+
# implement a validate() method that takes a single hash argument. When the user submits
|
142
|
+
# the login form, the username and password they entered is passed to validate()
|
143
|
+
# as a hash under :username and :password keys. In the future, this hash
|
144
|
+
# might also contain other data such as the domain that the user is logging in to.
|
145
|
+
#
|
146
|
+
# To use your custom authenticator, specify it's class name in the authenticator section
|
147
|
+
# of the config. You will also probably have to load the class using using a `require`
|
148
|
+
# call at the top of casserver.rb. Any other parameters you specify in the authenticator
|
149
|
+
# configuration will be passed on to the authenticator and made availabe in the validate()
|
150
|
+
# method as an @options hash.
|
151
|
+
#
|
152
|
+
# Example:
|
153
|
+
#
|
154
|
+
#authenticator:
|
155
|
+
# class: FooModule::MyCustomAuthenticator
|
156
|
+
# option_a: foo
|
157
|
+
# another_option: yeeha
|
158
|
+
|
159
|
+
|
160
|
+
##### LOOK & FEEL ######################################################################
|
161
|
+
|
162
|
+
# Set the path to the theme directory that determines how your CAS pages look.
|
163
|
+
#
|
164
|
+
# Custom themes are not well supported yet, but will be in the near future. In the
|
165
|
+
# meantime, if you want to create a custom theme, you can create a subdirectory
|
166
|
+
# under the CASServer's themes dir (for example '/usr/lib/ruby/1.8/gems/casserver-xxx/lib/themes',
|
167
|
+
# if you installed CASServer on Linux as a gem). A theme is basically just a theme.css
|
168
|
+
# file that overrides the themes/cas.css styles along with a collection of image files
|
169
|
+
# like logo.png and bg.png.
|
170
|
+
#
|
171
|
+
# By default, we use the 'simple' theme which you can find in themes/simple.
|
172
|
+
theme: simple
|
173
|
+
|
174
|
+
# The name of your company/organization. This will show up on the login page.
|
175
|
+
organization: CAS
|
176
|
+
|
177
|
+
# A short bit of text that shows up on the login page. You can make this blank if you prefer.
|
178
|
+
infoline: Powered by <a href="http://code.google.com/p/rubycas-server/">RubyCAS-Server</a>
|
179
|
+
|
180
|
+
|
181
|
+
##### LOGGING #########################################################################
|
182
|
+
|
183
|
+
# Configure general logging. This log is where you'll want to look in case of problems.
|
184
|
+
#
|
185
|
+
# You may want to change the file to something like /var/log/casserver.log
|
186
|
+
# Set the level to DEBUG if you want more detailed logging.
|
187
|
+
|
188
|
+
log:
|
189
|
+
file: /var/log/casserver.log
|
190
|
+
level: INFO
|
191
|
+
|
192
|
+
|
193
|
+
# If you want full database logging, uncomment this next section.
|
194
|
+
# Every SQL query will be logged here. This is useful for debugging database problems.
|
195
|
+
#
|
196
|
+
#db_log:
|
197
|
+
# file: /var/log/casserver_db.log
|
data/lib/casserver.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# change to current directory when invoked on its own
|
4
|
+
Dir.chdir(File.dirname(File.expand_path(__FILE__))) if __FILE__ == $0
|
5
|
+
|
6
|
+
# add current directory to load path
|
7
|
+
$: << File.dirname(File.expand_path(__FILE__))
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require_gem 'camping', '~> 1.5'
|
11
|
+
require 'camping'
|
12
|
+
|
13
|
+
require 'active_support'
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
# enable xhtml source code indentation for debugging views
|
17
|
+
Markaby::Builder.set(:indent, 2)
|
18
|
+
|
19
|
+
# seed the random number generator (ruby does this by default, but it doesn't hurt to do it here just to be sure)
|
20
|
+
srand
|
21
|
+
|
22
|
+
# Camping.goes must be called after the authenticator class is loaded, otherwise weird things happen
|
23
|
+
Camping.goes :CASServer
|
24
|
+
|
25
|
+
module CASServer
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'casserver/utils'
|
29
|
+
require 'casserver/models'
|
30
|
+
require 'casserver/cas'
|
31
|
+
require 'casserver/conf'
|
32
|
+
require 'casserver/views'
|
33
|
+
require 'casserver/controllers'
|
34
|
+
|
35
|
+
# init the logger
|
36
|
+
$LOG = CASServer::Utils::Logger.new(CASServer::Conf.log[:file])
|
37
|
+
$LOG.level = "CASServer::Utils::Logger::#{CASServer::Conf.log[:level]}".constantize
|
38
|
+
|
39
|
+
# do initialization stuff
|
40
|
+
def CASServer.create
|
41
|
+
CASServer::Models.create_schema
|
42
|
+
|
43
|
+
$LOG.info("RubyCAS-Server initialized.")
|
44
|
+
|
45
|
+
$LOG.debug("Configuration is:\n#{$CONF.to_yaml}")
|
46
|
+
$LOG.debug("Authenticator is: #{$AUTH}")
|
47
|
+
|
48
|
+
CASServer::Models::ServiceTicket.cleanup_expired(CASServer::Conf.service_ticket_expiry)
|
49
|
+
CASServer::Models::LoginTicket.cleanup_expired(CASServer::Conf.login_ticket_expiry)
|
50
|
+
CASServer::Models::ProxyGrantingTicket.cleanup_expired(CASServer::Conf.proxy_granting_ticket_expiry)
|
51
|
+
CASServer::Models::TicketGrantingTicket.cleanup_expired(CASServer::Conf.ticket_granting_ticket_expiry)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# this gets run if we launch directly (i.e. `ruby casserver.rb` rather than `camping casserver`)
|
56
|
+
if __FILE__ == $0 || $RUN
|
57
|
+
CASServer::Models::Base.establish_connection(CASServer::Conf.database)
|
58
|
+
if CASServer::Conf.db_log
|
59
|
+
CASServer::Models::Base.logger = Logger.new(CASServer::Conf.db_log[:file] || 'casserver_db.log')
|
60
|
+
CASServer::Models::Base.logger.level = "CASServer::Utils::Logger::#{CASServer::Conf.db_log[:level] || 'DEBUG'}".constantize
|
61
|
+
end
|
62
|
+
|
63
|
+
case CASServer::Conf.server
|
64
|
+
when "webrick", :webrick
|
65
|
+
require 'webrick/httpserver'
|
66
|
+
require 'webrick/https'
|
67
|
+
require 'camping/webrick'
|
68
|
+
|
69
|
+
# TODO: verify the certificate's validity
|
70
|
+
# example of how to do this is here: http://pablotron.org/download/ruri-20050331.rb
|
71
|
+
|
72
|
+
cert_path = CASServer::Conf.ssl_cert
|
73
|
+
key_path = CASServer::Conf.ssl_key || CASServer::Conf.ssl_cert
|
74
|
+
# look for the key in the ssl_cert if no ssl_key is specified
|
75
|
+
|
76
|
+
raise "'#{cert_path}' is not a valid ssl certificate. Your 'ssl_cert' configuration" +
|
77
|
+
" setting must be a path to a valid ssl certificate file." unless
|
78
|
+
File.exists? cert_path
|
79
|
+
|
80
|
+
raise "'#{key_path}' is not a valid ssl private key. Your 'ssl_key' configuration" +
|
81
|
+
" setting must be a path to a valid ssl private key file." unless
|
82
|
+
File.exists? key_path
|
83
|
+
|
84
|
+
cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
85
|
+
key = OpenSSL::PKey::RSA.new(File.read(key_path))
|
86
|
+
|
87
|
+
begin
|
88
|
+
s = WEBrick::HTTPServer.new(
|
89
|
+
:BindAddress => "0.0.0.0",
|
90
|
+
:Port => CASServer::Conf.port,
|
91
|
+
:SSLEnable => true,
|
92
|
+
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
93
|
+
:SSLCertificate => cert,
|
94
|
+
:SSLPrivateKey => key
|
95
|
+
)
|
96
|
+
rescue Errno::EACCES
|
97
|
+
puts "\nThe server could not launch. Are you running on a privileged port? (e.g. port 443) If so, you must run the server as root."
|
98
|
+
exit 2
|
99
|
+
end
|
100
|
+
|
101
|
+
CASServer.create
|
102
|
+
s.mount "#{CASServer::Conf.uri_path}", WEBrick::CampingHandler, CASServer
|
103
|
+
|
104
|
+
puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'\n\n"
|
105
|
+
|
106
|
+
# This lets Ctrl+C shut down your server
|
107
|
+
trap(:INT) do
|
108
|
+
s.shutdown
|
109
|
+
end
|
110
|
+
|
111
|
+
s.start
|
112
|
+
|
113
|
+
when "mongrel", :mongrel
|
114
|
+
require 'rubygems'
|
115
|
+
require 'mongrel/camping'
|
116
|
+
|
117
|
+
# camping has fixes for mongrel currently only availabe in SVN
|
118
|
+
# ... you can install camping from svn (1.5.180) by running:
|
119
|
+
# gem install camping --source code.whytheluckystiff.net
|
120
|
+
require_gem 'camping', '~> 1.5.180'
|
121
|
+
|
122
|
+
CASServer.create
|
123
|
+
|
124
|
+
begin
|
125
|
+
server = Mongrel::Camping::start("0.0.0.0",CASServer::Conf.port,"#{CASServer::Conf.uri_path}",CASServer)
|
126
|
+
rescue Errno::EACCES
|
127
|
+
puts "\nThe server could not launch. Are you running on a privileged port? (e.g. port 443) If so, you must run the server as root."
|
128
|
+
exit 2
|
129
|
+
end
|
130
|
+
|
131
|
+
puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'"
|
132
|
+
server.run.join
|
133
|
+
|
134
|
+
when "fastcgi", :fastcgi
|
135
|
+
require 'camping/fastcgi'
|
136
|
+
Dir.chdir('/srv/www/camping/casserver/')
|
137
|
+
|
138
|
+
CASServer.create
|
139
|
+
Camping::FastCGI.start(CASServer)
|
140
|
+
|
141
|
+
when "cgi", :cgi
|
142
|
+
CASServer.create
|
143
|
+
puts CASServer.run
|
144
|
+
|
145
|
+
else
|
146
|
+
if CASServer::Conf.server
|
147
|
+
raise "The server setting '#{CASServer::Conf.server}' in your config.yml file is invalid."
|
148
|
+
else
|
149
|
+
raise "You must have a 'server' setting in your config.yml file. Please see the RubyCAS-Server documentation."
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CASServer
|
2
|
+
module Authenticators
|
3
|
+
class Base
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
def validate(credentials)
|
7
|
+
raise NotImplementedError, "This method must be implemented by a class extending #{self.class}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def configure(options)
|
11
|
+
raise ArgumentError, "options must be a HashWithIndifferentAccess" unless options.kind_of? HashWithIndifferentAccess
|
12
|
+
@options = options.dup
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def read_standard_credentials(credentials)
|
17
|
+
@username = credentials[:username]
|
18
|
+
@password = credentials[:password]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'casserver/authenticators/base'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'net/ldap'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
require_gem 'ruby-net-ldap', '~> 0.0.4'
|
8
|
+
require 'net/ldap'
|
9
|
+
end
|
10
|
+
|
11
|
+
class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
12
|
+
def validate(credentials)
|
13
|
+
read_standard_credentials(credentials)
|
14
|
+
|
15
|
+
raise "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
16
|
+
raise "Invalid authenticator configuration!" unless @options[:ldap]
|
17
|
+
raise "You must specify an ldap server in the configuration!" unless @options[:ldap][:server]
|
18
|
+
|
19
|
+
ldap = Net::LDAP.new
|
20
|
+
ldap.host = @options[:ldap][:server]
|
21
|
+
ldap.port = @options[:ldap][:port] if @options[:ldap][:port]
|
22
|
+
|
23
|
+
if @options[:ldap][:auth_user]
|
24
|
+
raise "A password must be specified in the configuration for the authenticator user!" unless @options[:ldap][:auth_password]
|
25
|
+
ldap.authenticate(@options[:ldap][:auth_user], @options[:ldap][:auth_password])
|
26
|
+
end
|
27
|
+
|
28
|
+
filter = "(#{@options[:ldap][:username_attribute] || default_username_attribute}=#{@username})"
|
29
|
+
filter += " & (#{@options[:ldap][:filter]})" if @options[:ldap][:filter]
|
30
|
+
|
31
|
+
result = ldap.bind_as(:base => @options[:ldap][:base], :filter => filter, :password => @password)
|
32
|
+
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def default_username_attribute
|
38
|
+
"uid"
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'casserver/authenticators/base'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'active_record'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
require 'active_record'
|
8
|
+
end
|
9
|
+
|
10
|
+
class CASServer::Authenticators::SQL < CASServer::Authenticators::Base
|
11
|
+
|
12
|
+
def validate(credentials)
|
13
|
+
read_standard_credentials(credentials)
|
14
|
+
|
15
|
+
raise "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
16
|
+
raise "Invalid authenticator configuration!" unless @options[:database]
|
17
|
+
|
18
|
+
CASUser.establish_connection @options[:database]
|
19
|
+
CASUser.set_table_name @options[:user_table] || "users"
|
20
|
+
|
21
|
+
username_column = @options[:username_column] || 'username'
|
22
|
+
password_column = @options[:password_column] || 'password'
|
23
|
+
|
24
|
+
results = CASUser.find(:all, :conditions => ["#{username_column} = ? AND #{password_column} = ?", @username, @password])
|
25
|
+
|
26
|
+
if results.size > 0
|
27
|
+
$LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
|
28
|
+
return true
|
29
|
+
else
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CASUser < ActiveRecord::Base
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|