├── .gitignore ├── CHANGELOG ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── bin └── rubycas-server ├── config.ru ├── config ├── config.example.yml └── unicorn.rb ├── db ├── .gitignore └── migrate │ └── 001_create_initial_structure.rb ├── lib ├── casserver.rb └── casserver │ ├── authenticators │ ├── active_directory_ldap.rb │ ├── active_resource.rb │ ├── authlogic_crypto_providers │ │ ├── aes256.rb │ │ ├── bcrypt.rb │ │ ├── md5.rb │ │ ├── sha1.rb │ │ └── sha512.rb │ ├── base.rb │ ├── client_certificate.rb │ ├── google.rb │ ├── ldap.rb │ ├── ntlm.rb │ ├── open_id.rb │ ├── sql.rb │ ├── sql_authlogic.rb │ ├── sql_encrypted.rb │ ├── sql_md5.rb │ ├── sql_rest_auth.rb │ └── test.rb │ ├── cas.rb │ ├── localization.rb │ ├── model.rb │ ├── server.rb │ ├── utils.rb │ └── views │ ├── _login_form.erb │ ├── layout.erb │ ├── login.erb │ ├── proxy.builder │ ├── proxy_validate.builder │ ├── service_validate.builder │ └── validate.erb ├── log └── .gitignore ├── po ├── de_DE │ └── rubycas-server.po ├── es_ES │ └── rubycas-server.po ├── fr_FR │ └── rubycas-server.po ├── ja_JP │ └── rubycas-server.po ├── pl_PL │ └── rubycas-server.po ├── pt_BR │ └── rubycas-server.po ├── ru_RU │ └── rubycas-server.po ├── rubycas-server.pot ├── zh_CN │ └── rubycas-server.po └── zh_TW │ └── rubycas-server.po ├── public └── themes │ ├── cas.css │ ├── notice.png │ ├── ok.png │ ├── simple │ ├── bg.png │ ├── favicon.png │ ├── login_box_bg.png │ ├── logo.png │ └── theme.css │ ├── urbacon │ ├── bg.png │ ├── login_box_bg.png │ ├── logo.png │ └── theme.css │ └── warning.png ├── resources ├── diagrams │ ├── basic_cas_single_signon_mechanism_diagram.png │ └── basic_cas_single_signon_mechanism_diagram.svg └── init.d.sh ├── rubycas-server.gemspec ├── setup.rb ├── spec ├── alt_config.yml ├── authenticators │ ├── active_resource_spec.rb │ └── ldap_spec.rb ├── casserver_spec.rb ├── default_config.yml ├── model_spec.rb ├── spec.opts ├── spec_helper.rb └── utils_spec.rb └── tasks ├── bundler.rake ├── db └── migrate.rake ├── localization.rake └── spec.rake /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | config.yml 3 | *.db 4 | *.sqlite3 5 | *.swp 6 | *~ 7 | *.pidaproject 8 | *.log 9 | *.mo 10 | pkg 11 | ssl 12 | custom/* 13 | .DS_Store 14 | /nbproject 15 | .irbrc_history 16 | resources/dev 17 | .rvmrc 18 | .bundle 19 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | === 1.0.1 :: In Progress... 2 | 3 | * NEW: 4 | * On startup the server now checks for a config.yml file in its own root directory, 5 | then in /etc/rubycas-server. 6 | 7 | * FIXED: 8 | * Specs now pass under Active Record 2.3.12 9 | 10 | === 1.0.0 :: 2011-08-03 11 | 12 | * NEW: 13 | * Rewrite to replace Camping/Picnic with Sinatra 14 | * Support for Ruby 1.9.2 15 | * Support for Active Record 3 16 | 17 | * CHANGED: 18 | * Google authenticator proxy configuration has been changed (see config.example.yml) 19 | 20 | === 0.8.0 21 | 22 | * NEW: 23 | * Support for localization via Ruby-GetText. 24 | See http://code.google.com/p/rubycas-server/wiki/Localization 25 | for details. [antono] 26 | * Switched to Picnic 0.8.x, so RubyCAS-Server is now based on Rack 27 | and Camping 2.0 and is now compatible with Passenger Phusion 28 | * Change to authenticator API: every authenticator now has a class 'setup' 29 | method that gets called at server startup. This is where class-level 30 | configuration should be done (e.g. establishing a database connection). 31 | This is different from the 'configure' method which gets called on a per- 32 | instance basis for each authenticator. [godfat] 33 | * Database connections are now automatically released back to the connection 34 | pool at the end of each request. This should allow the server to handle 35 | many more concurrent requests, since database connections are no longer left 36 | checked out of the pool. 37 | * Added new SQL authenticator (sql_rest_auth) compatible with the 38 | restful_authentication Rails plugin. [antono] 39 | * Re-licensed under the MIT License. 40 | 41 | * FIXED: 42 | * Fixed weird problems with loading controllers when using older versions of 43 | activesupport and/or rubygems. 44 | * Failure to connect to a service during a single sign out request is now 45 | handled gracefully. 46 | * Required gem dependencies have been re-enabled in the gemspec. 47 | * Authlogic authenticator files added to gemspec. [rajiv] 48 | * Authenticators are now instantiated on a per-request basis (rather than 49 | once at startup) to ensure thread safety. 50 | 51 | === 0.7.1 :: 2008-11-10 52 | 53 | * Fixed dependency loading problems introduced by upstream changes in RubyGems 54 | 1.3.1. 55 | 56 | === 0.7.0 :: 2008-11-04 57 | 58 | * NEW: 59 | * Implemented single-sign-out functionality as specified in CAS 3.3. See 60 | http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out. 61 | * It is now possible to configure Authenticators to return extra attributes 62 | to CAS clients alongside the username. For an example of how to do this see 63 | the included SQL authenticator. Also have a look at: 64 | http://groups.google.com/group/rubycas-server/browse_thread/thread/5eade3793cb590e9 65 | Note that extra attributes of type other than String or Numeric are serialized 66 | into YAML format before being sent along to the client. 67 | * Added an MD5-password version of the SQL authenticator for Drupal and any other 68 | database that stores its passwords in hashed form (thanks malcolmm). 69 | * Added new Google authenticator for authenticating against Google/GMail 70 | accounts. 71 | 72 | * CHANGED: 73 | * Service URIs are now automatically normalized. For example, if the service 74 | URI given to the server has a 'ticket' parameter, the ticket will now be 75 | automatically stripped. This is to avert any possible issues raised by 76 | misbehaving CAS clients (the CAS ticket should never be part of the service 77 | URI). Same goes for other CAS-related parameters like 'service', 'renew', 78 | and 'gateway'. Additionally, the trailing '/' and '?' characters are 79 | automatically stripped from URLs, since, for example, "http://google.com/" 80 | is almost certainly equivalent to "http://google.com". 81 | * The expire_sessions config variable is now respected -- ticket granting 82 | ticket cookies are set with an expiry datetime, so that the SSO session 83 | is effectively terminated once the ticket_granting_ticket_expiry period 84 | is reached. 85 | * If present, the HTTP_X_FORWARDED_FOR header is used for recording the 86 | client's address. This is useful when the server is running behind a reverse 87 | proxy, but it should not be considered authoritative since it can be 88 | easily spoofed. 89 | * The 'service' field in the 'casserver_st' table has been changed from 90 | VARCHAR(255) to TEXT in order to accomodate service URIs longer than 255 91 | characters (fixes issue #46). 92 | * The CAS XML responses are no longer whitespace-formatted (i.e. Markaby's 93 | auto-indentation has been turned off). Apparently the whitespace was 94 | causing problems with mod_auth_cas. See: 95 | http://groups.google.com/group/rubycas-server/browse_thread/thread/e482fe09999b73d3 96 | * When used without pre-authentication, the LDAP authenticator now tries to 97 | bind by searching for the given username in the LDAP directory based on the 98 | configured username_attribute. Prior to this change the authenticator 99 | attempted to bind with the LDAP server by assuming that the username credential 100 | matches the user's CN. This is no longer the case. 101 | * CAS responses to invalid requests (for example where required parameters 102 | are missing or incorrect) will now have HTTP status code 422. Internal server 103 | errors (where the server rather than the client is at fault) have error 500. 104 | Previously most responses had error code 200, regardless of their contents. 105 | 106 | * FIXED: 107 | * Fixed logout action to work properly with ActiveRecord 2.1 (eager loading behaviour 108 | was changed upstream forcing a change to the way we look for ProxyGrantingTickets 109 | to delete on logout). 110 | * When running under Mongrel, the USR2 signal should now restart the server as 111 | expected -- however currently this only works when the server is running 112 | in the foregaround. When daemonized, USR2 will shut down the server without 113 | restarting (see issue #58). 114 | * Fixed activerecord/activesupport gem load problems, hopefully once and for all 115 | (however picnic-0.7.0 is now required). 116 | 117 | === 0.6.0 :: 2008-03-28 118 | 119 | * Much of the supporting functionality that makes RubyCAS-Server 120 | act as a well-behaved Linux service has been abstracted out 121 | into its own library. This new library is called Picnic and is 122 | now a gem dependency for RubyCAS-Server. You can find out more about 123 | it at http://code.google.com/p/camping-picnic/. 124 | * The logout action will now accept a 'destination' parameter in lieu of 125 | 'service'. This means that if a 'destination' parameter is given with 126 | some URL, the logout action will show the login form, allowing the user 127 | to immedietly log back in to the service specified by 'destination'. 128 | * The logout action will now accept a 'url' parameter. If given, the logout 129 | page will show a message indicating that the CAS session has been terminated 130 | and instructing the user to click on a link to follow the given URL. If the 131 | 'url' parameter is given, the login form will NOT be shown on the logout 132 | page (see above). 133 | * When an authentication failure occurs (because the user submitted 134 | invalid credentials or the login ticket is missing), the server 135 | now returns a 401 (Unauthorized) response instead of 200. 136 | * An encryption-enabled version of the SQL authenticator is now 137 | available. For more info have a look at: 138 | http://code.google.com/p/rubycas-server/wiki/UsingTheSQLEncryptedAuthenticator 139 | * Better compatibility with Oracle databases. The database migration 140 | no longer tries to create tables with long names when long 141 | table names are not supported by the underlying database connector 142 | (issue #15). 143 | * The server now automatically removes leading and trailing whitespace from 144 | the username entered by users. Passwords however are left intact, with no 145 | whitespace removed. 146 | * The server can now be configured to automatically downcase the 147 | username entered by users (dowcase_username option). So if a user 148 | enters "JSmith", the system will convert it to "jsmith" if the 149 | downcase_username option is set to true. 150 | * The server can now be made to bind to a specific address. See the 151 | :bind_address option in the config.example.yml file. 152 | * Fixed bug with ActiveRecord 2.0.2 where service tickets were not 153 | being given a type (issue #37). 154 | 155 | === 0.5.1 :: 2007-12-20 156 | 157 | * Tickets generated by the server should now be a lot more secure. 158 | The random string generator used for generating tickets now uses 159 | Crypt::ISAAC. Tickets have also been extended in length; STs, PTs 160 | and LTs can now extend up to 32 characters, and PGTs and PGT-IOUs 161 | up to 64. 162 | 163 | === 0.5.0 :: 2007-09-20 164 | 165 | * Gateway requests should now be handled correctly. When the request to the 166 | login page is made with gateway=true as one of the parameters, the CAS 167 | server will immediately redirect back to the target service along with 168 | a service ticket if an SSO session exists for the user (or without a 169 | service ticket if there is no pre-existing SSO session). 170 | Note that if you are using RubyCAS-Client and want gatewaying, you will 171 | need to upgrade it to 1.1.0 as gatewaying was broken in prior versions. 172 | * If gateway=true is specified as part of the logout URI, the server will 173 | log the user out and immediately redirect them back to the specified 174 | service. In other words, you can now do "gatewayed logouts" as well 175 | as logins. 176 | * A login ticket can now be remotely requested from the server by placing 177 | a POST request to '/loginTicket'. 178 | * The login view can now be made to return only the login form. This is 179 | done by adding the 'onlyLoginForm' parameter to the '/login' request. 180 | Optionally, a 'submitToURI' parameter can be supplied to force the login 181 | form to submit to the given URI (otherwise the server will try to figure 182 | out the full URI to its own login controller). This functionality may be 183 | useful when you want to embed the login form in some external page, as 184 | an IFRAME otherwise. 185 | * Custom views can now be used to override the default Markaby templates 186 | by specifying a 'custom_views_file' option in the configuration. See 187 | custom_views.example.rb. [jzylks] 188 | * Table names have been shortened to work with Oracle. A migration has 189 | been added that should do the shortening for you the first time you run 190 | this new RubyCAS-Server version. 191 | * Multiple authenticators can now be specified. During authentication, 192 | credentials are presented to the first authenticator, then the second, 193 | and so on, until the user is validated by any one authenticator or fails 194 | validation for all of them. [jzylks] 195 | * When using webrick, you can now run with SSL disabled by omitting the 196 | ssl_cert and ssl_key parameters. 197 | * Changed incorrect MySQL example database configuration -- option should 198 | be 'host:' not 'server:' (issue #22). 199 | 200 | === 0.4.2 :: 2007-07-26 201 | 202 | * The LDAP/AD authenticator has been largely re-written. The code is a bit 203 | cleaner now, and should work better with non-Active Directory LDAP servers 204 | (although this has yet to be tested since I don't have access to a non-AD 205 | LDAP server). 206 | * The validate() method in your authenticators now receives a :service element 207 | (in addition to :username, and :password). This is simply the service 208 | url (if any) specified in the user's CAS request. If you call 209 | read_standard_credentials(credentials) at the top of your validator, the value 210 | will also be available as @service along with @username and @password. 211 | * By request, a :username_prefix option has been added to the ldap 212 | configuration. If entered, this string will be automatically prefixed to 213 | the username entered by the user. 214 | * A bug having to do with handling authenticator errors has been fixed. 215 | Any authenticator error messages should now be correctly shown on the 216 | login page. 217 | * Minor improvements to error messages having to do with login tickets. 218 | They're a bit more prescriptive now, explaining to the user what steps 219 | they should take to correct the error. 220 | 221 | === 0.4.1 :: 2007-06-07 222 | 223 | * This release restores compatiblity with older versions of rubygems 224 | (pre-0.9.0). To achieve this, we alias the 'gem' method to the old 225 | 'require_gem' if 'gem' is not already defined. 226 | * rubycas-server-ctl will now quiety delete an orphaned .pid file 227 | instead complaining loudly and refusing to start up. 228 | * Fixed minor bug in rubycas-server-ctl that sometimes incorrectly reported 229 | startup problems when in fact the server had started just fine. 230 | 231 | 232 | === 0.4.0 :: 2007-06-05 233 | 234 | * Added rubycas-server-ctl script for controlling daemonized server. 235 | * rubygems-0.9.0 or later is now required. 236 | * Added system startup script to be used in /etc/init.d on Linux systems. 237 | * Authenticator can now be loaded from an external file using the 'source' 238 | configuration option. 239 | * Better preemptive detection of startup problems with mongrel. 240 | * User now sees an error message if the service URI is not a valid URI (i.e. 241 | if it's not URI-encoded or otherwise malformed). 242 | 243 | 244 | === 0.3.0 :: 2007-03-29 245 | 246 | * Fixed glaring security problem with LDAP/AD Authenticator where under some 247 | circumstances blank passwords were accepted as valid. 248 | * Autocomplete has been turned off on the password field for better security. 249 | In the future we may allow autocomplete to be re-enabled using a 250 | configuration setting. 251 | * When the user visits the login page and is already authenticated (i.e. they 252 | have a valid ticket granting cookie), a message is shown at the top 253 | indicating that they are already logged in. 254 | * sqlite3-ruby is no longer required by the gem as a dependency. The user 255 | must now install it manually prior to installing rubycas-server. The 256 | building of sqlite3 native extensions appears to be somewhat flakey 257 | and probably defeats the original purpose of using it (which was 258 | to have a CAS server up and running with no additional DB configuration). 259 | We will use MySQL as the default database adapter instead, since it does 260 | not require additional libraries and many users will have a MySQL server 261 | already available. 262 | * Fixed bug that was causing all proxy-granting tickets to be deleted whenever 263 | any user logged out. Only the PGTs for the user that is logging out are now 264 | being deleted. 265 | * Trailing slashes in service URLs are now ignored when validating service 266 | and proxy tickets (e.g. "http://www.google.com" and "http://www.google.com/" 267 | are now considered to be the same service URL). 268 | * Authenticators now raise AuthenticatorError exceptions when encountering 269 | a problem/error. This makes it easier to send feedback to the user. 270 | However, other exceptions should still be raised when errors ought 271 | not be recoverable (i.e. programming errors). 272 | * Fixed serious vulnerability in LDAP authenticator where under some 273 | cirumstances the user could just enter '*' as their username to match 274 | any username. The LDAP authenticator will now refuse to process logins 275 | with usernames that contain the characters * ( ) \ / and the NULL 276 | character \0. 277 | * Views are no longer xhtml-validated. Markaby's auto-validation was turned 278 | off to allow for use of the autocomplete property on inputs, since this is 279 | the only viable way of turning off password storage in IE and Firefox at 280 | the page level. 281 | * You can now limit the maximum length of a login session by setting the 282 | expire_sessions config setting to true. 283 | * Fixed some minor bugs in the login view. 284 | 285 | 286 | === 0.2.0 :: 2007-03-20 287 | 288 | * ruby-casserver now behaves more like a real command-line app, accepting 289 | various command line arguments including -h (help), -v (version), -c (use 290 | an alternate config.yml), and -d (daemonize, when using webrick or mongrel 291 | mode). 292 | * Special characters in CAS XML responses are now properly encoded into XML 293 | entities 294 | * CAS XML responses are no longer auto-indented... Markaby's indentation 295 | seemed to be causing problems with the PHP CAS client. 296 | * Misc minor bug fixes/cleanup. 297 | 298 | 299 | === 0.1.0 :: 2007-03-01 300 | 301 | * First public release. 302 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | gemspec 3 | 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rubycas-server (1.0) 5 | activerecord (~> 2.3.12) 6 | activesupport (~> 2.3.12) 7 | crypt-isaac (~> 0.9.1) 8 | gettext (~> 2.1.0) 9 | sinatra (~> 1.0) 10 | 11 | GEM 12 | remote: http://rubygems.org/ 13 | specs: 14 | activerecord (2.3.12) 15 | activesupport (= 2.3.12) 16 | activeresource (2.3.12) 17 | activesupport (= 2.3.12) 18 | activesupport (2.3.12) 19 | capybara (0.4.1.2) 20 | celerity (>= 0.7.9) 21 | culerity (>= 0.2.4) 22 | mime-types (>= 1.16) 23 | nokogiri (>= 1.3.3) 24 | rack (>= 1.0.0) 25 | rack-test (>= 0.5.4) 26 | selenium-webdriver (>= 0.0.27) 27 | xpath (~> 0.1.3) 28 | celerity (0.8.8) 29 | childprocess (0.1.7) 30 | ffi (~> 0.6.3) 31 | crypt-isaac (0.9.1) 32 | culerity (0.2.15) 33 | diff-lcs (1.1.2) 34 | ffi (0.6.3) 35 | rake (>= 0.8.7) 36 | gettext (2.1.0) 37 | locale (>= 2.0.5) 38 | json_pure (1.5.1) 39 | locale (2.0.5) 40 | mime-types (1.16) 41 | net-ldap (0.1.1) 42 | nokogiri (1.4.4) 43 | rack (1.2.1) 44 | rack-test (0.5.7) 45 | rack (>= 1.0) 46 | rake (0.8.7) 47 | rspec (2.5.0) 48 | rspec-core (~> 2.5.0) 49 | rspec-expectations (~> 2.5.0) 50 | rspec-mocks (~> 2.5.0) 51 | rspec-core (2.5.1) 52 | rspec-expectations (2.5.0) 53 | diff-lcs (~> 1.1.2) 54 | rspec-mocks (2.5.0) 55 | rubyzip (0.9.4) 56 | selenium-webdriver (0.1.3) 57 | childprocess (~> 0.1.5) 58 | ffi (~> 0.6.3) 59 | json_pure 60 | rubyzip 61 | sinatra (1.1.3) 62 | rack (~> 1.1) 63 | tilt (< 2.0, >= 1.2.2) 64 | sqlite3 (1.3.3) 65 | tilt (1.2.2) 66 | xpath (0.1.3) 67 | nokogiri (~> 1.3) 68 | 69 | PLATFORMS 70 | ruby 71 | 72 | DEPENDENCIES 73 | activeresource (~> 2.3.12) 74 | capybara 75 | net-ldap (~> 0.1.1) 76 | rack-test 77 | rspec 78 | rspec-core 79 | rubycas-server! 80 | sqlite3 (~> 1.3.1) 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Portions of RubyCAS-Server contributed by Matt Zukowski are copyright (c) 2009 Urbacon Ltd. 2 | Other portions are copyright of their respective authors. 3 | 4 | The MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MOVED! 2 | 3 | This repo has been moved to https://github.com/rubycas/rubycas-server. 4 | 5 | The fork you are looking at is no longer updated. Please change your git remotes to the new rubycas URL. -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | Dir['tasks/**/*.rake'].each { |rake| load rake } -------------------------------------------------------------------------------- /bin/rubycas-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Enables UTF-8 compatibility in ruby 1.8. 4 | $KCODE = 'u' if RUBY_VERSION < '1.9' 5 | 6 | require 'rubygems' 7 | 8 | $:.unshift File.dirname(__FILE__) + "/../lib" 9 | 10 | if ARGV.join.match('--debugger') 11 | require 'ruby-debug' 12 | puts 13 | puts "=> Debugger Enabled" 14 | end 15 | 16 | if ARGV.join.match('-c') 17 | c = ARGV.join.match(/-c\s*([^\s]+)/) 18 | if (c && c[1]) 19 | ENV['CONFIG_FILE'] = c[1] 20 | puts 21 | puts "=> Using custom config file #{ENV['CONFIG_FILE'].inspect}" 22 | else 23 | $stderr.puts("To specify a custom config file use `rubycas-server -c path/to/config_file_name.yml`.") 24 | exit 25 | end 26 | end 27 | 28 | require 'casserver' 29 | 30 | CASServer::Server.run! 31 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | 4 | $:.unshift "#{File.dirname(__FILE__)}/lib" 5 | require "casserver" 6 | 7 | use Rack::ShowExceptions 8 | use Rack::Runtime 9 | use Rack::CommonLogger 10 | 11 | run CASServer::Server.new 12 | -------------------------------------------------------------------------------- /config/config.example.yml: -------------------------------------------------------------------------------- 1 | # IMPORTANT NOTE ABOUT YAML CONFIGURATION FILES 2 | # ---> Be sure to use spaces instead of tabs for indentation. YAML is 3 | # white-space sensitive! 4 | 5 | ##### SERVER SETUP ################################################################ 6 | 7 | # There are several ways to run RubyCAS-Server: 8 | # 9 | # webrick -- stand-alone WEBrick server; should work out-of-the-box; this is 10 | # the default method, but probably not suited for high-traffic usage 11 | # mongrel -- stand-alone Mongrel server; fast, but you'll need to install 12 | # and compile Mongrel and run it behind an https reverse proxy like 13 | # Pound or Apache 2.2's mod_proxy (since Mongrel cannot serve out 14 | # over SSL on its own). 15 | # passenger -- served out by Apache via the mod_rails/mod_rack module 16 | # (see http://www.modrails.com/) 17 | # 18 | # The following are exampe configurations for each of these three methods: 19 | # 20 | 21 | 22 | ### 23 | ### WEBrick example 24 | ### 25 | # WEBrick is a simple, all-Ruby web server. This is the easiest method for running 26 | # RubyCAS-Server. All you need is an SSL certificate (enter its path under the 27 | # ssl_cert option). WEBrick is fine for sites with low to medium traffic, but for 28 | # high-performance scenarios you may want to look into deploying using Mongrel 29 | # or Passenger. 30 | 31 | server: webrick 32 | port: 443 33 | ssl_cert: /path/to/your/ssl.pem 34 | 35 | # If your private key is in a separate file from the cert 36 | 37 | #ssl_key: /path/to/your/private_key.pem 38 | 39 | # If you do not already have an SSL certificate and would like to automatically 40 | # generate one, run the "generate_ssl_certificate" rake task and use the following 41 | # settings: 42 | 43 | # ssl_cert: ssl/cert.pem 44 | # ssl_key: ssl/key.pem 45 | 46 | 47 | # By default the login page will be available at the root path 48 | # (e.g. https://login.example.net/). The uri_path option lets you serve it from a 49 | # different path (e.g. https://login.example.net/cas). 50 | 51 | #uri_path: /cas 52 | 53 | 54 | # This lets you bind the server to a specific address. Use 0.0.0.0 to listen on 55 | # all available interfaces (this is the default). 56 | 57 | #bind_address: 0.0.0.0 58 | 59 | 60 | ### 61 | ### Mongrel example 62 | ### 63 | # Mongrel is much faster than WEBrick, but there are two caveats: 64 | # 1. Since Mongrel can't serve out encrypted HTTP on its own (and CAS requires this), 65 | # you will have to set up a reverse proxy like Pound or Apache's mod_proxy and 66 | # route through it requests to the Mongrel server. So for example, 67 | # your Pound server will receive all of the requests to RubyCAS-Server on port 443, 68 | # and forward them to the Mongrel server listening on port 11011. 69 | # 2. Some of Mongrel's components are compiled into native binaries, so if you are 70 | # installing on Linux, make sure you have all of the standard build tools 71 | # available. The binaries should be automatically compiled for you when you 72 | # install the mogrel gem (if you're runnings Windows, pre-compiled 73 | # binaries will be downloaded and installed, so don't worry about this). 74 | 75 | #server: mongrel 76 | #port: 11011 77 | 78 | 79 | # Bind the server to a specific address. Use 0.0.0.0 to listen on all 80 | # available interfaces (this is the default). 81 | 82 | #bind_address: 0.0.0.0 83 | 84 | ### Reverse proxy configuration examples 85 | # If you're using mod_proxy, your Apache vhost config should look something like this: 86 | # 87 | # Listen 443 88 | # 89 | # ServerAdmin admin@example.net 90 | # ServerName login.example.net 91 | # 92 | # SSLEngine On 93 | # SSLCertificateFile /etc/apache2/ssl.crt/example.pem 94 | # 95 | # # Don't do forward proxying, we only want reverse proxying 96 | # ProxyRequests Off 97 | # 98 | # 99 | # Order allow,deny 100 | # Allow from all 101 | # BalancerMember http://127.0.0.1:11011 102 | # 103 | # 104 | # 105 | # For Pound, the config should be something like: 106 | # 107 | # ListenHTTPS 108 | # Address 0.0.0.0 109 | # Port 11011 110 | # Cert "/etc/ssl/example.pem" 111 | # 112 | # Service 113 | # BackEnd 114 | # Address localhost 115 | # Port 443 116 | # End 117 | # End 118 | # End 119 | 120 | 121 | ### 122 | ### Phusion Passenger (running under Apache configured for SSL) 123 | ### 124 | 125 | # No additional configuration is requried to run RubyCAS-Server under 126 | # passsenger. Just follow the normal instructions for a Passenger app 127 | # (see http://www.modrails.com/). 128 | # 129 | # Here's an example Apache vhost config for RubyCAS-Server and Passenger: 130 | # 131 | # Listen 443 132 | # 133 | # ServerAdmin admin@example.net 134 | # ServerName login.example.net 135 | # 136 | # SSLEngine On 137 | # SSLCertificateFile /etc/apache2/ssl.crt/example.pem 138 | # 139 | # RailsAutoDetect off 140 | # 141 | # DocumentRoot /usr/lib/ruby/gems/1.8/gems/rubycas-server-0.8.0/public 142 | # 143 | # 144 | # AllowOverride all 145 | # Allow from all 146 | # 147 | # 148 | # 149 | 150 | 151 | ##### DATABASE ################################################################# 152 | 153 | # Set up the database connection. Make sure that this database is secure! 154 | # 155 | # By default, we use MySQL, since it is widely used and does not require any 156 | # additional ruby libraries besides ActiveRecord. 157 | # 158 | # With MySQL, your config would be something like the following: 159 | # (be sure to create the casserver database in MySQL beforehand, 160 | # i.e. `mysqladmin -u root create casserver`) 161 | 162 | database: 163 | adapter: mysql 164 | database: casserver 165 | username: root 166 | password: 167 | host: localhost 168 | reconnect: true 169 | 170 | # IMPORTANT! By default, the server can handle up to ~5 concurrent requests 171 | # (without queuing). You can increase this by setting the database connection 172 | # pool size to a higher number. For example, to handle up to ~10 concurrent 173 | # requests: 174 | # 175 | #database: 176 | # pool: 10 177 | # adapter: mysql 178 | # database: casserver 179 | # username: root 180 | # password: 181 | # host: localhost 182 | 183 | # 184 | # Instead of MySQL you can use SQLite3, PostgreSQL, MSSQL, or anything else 185 | # supported by ActiveRecord. 186 | # 187 | # With SQLite3 (which does not require a separate database server), your 188 | # configuration would look something like the following (don't forget to install 189 | # the sqlite3-ruby gem beforehand!): 190 | 191 | #database: 192 | # adapter: sqlite3 193 | # database: /var/lib/casserver.db 194 | 195 | 196 | # By default RubyCAS-Server will run migrations at every startup to ensure 197 | # that its database schema is up-to-date. To disable this behaviour set 198 | # the following option to true: 199 | 200 | #disable_auto_migrations: true 201 | 202 | ##### AUTHENTICATION ########################################################### 203 | 204 | # Configure how username/passwords are validated. 205 | # 206 | # !!! YOU MUST CONFIGURE AT LEAST ONE OF THESE AUTHENTICATION METHODS !!! 207 | # 208 | # There are several built-in methods for authentication: 209 | # SQL, ActiveDirectory, LDAP, and GoogleAccounts. If none of these work for you, 210 | # it is relatively easy to write your own custom Authenticator class (see below). 211 | # 212 | # === SQL Authentication ======================================================= 213 | # 214 | # The simplest method is to validate against a SQL database. This assumes 215 | # that all of your users are stored in a table that has a 'username' column 216 | # and a 'password' column. When the user logs in, CAS connects to this database 217 | # and looks for a matching username/password in the users table. If a matching 218 | # username and password is found, authentication is successful. 219 | # 220 | # If you prefer to have your passwords stored in an encrypted form, have a 221 | # look at the SQLEncrypted authenticator: 222 | # http://code.google.com/p/rubycas-server/wiki/UsingTheSQLEncryptedAuthenticator 223 | # 224 | # If your users table stores passwords with MD5 hashing (for example as with 225 | # Drupal) try using the SQLMd5 version of the SQL authenticator. 226 | # 227 | # Example: 228 | # 229 | #authenticator: 230 | # class: CASServer::Authenticators::SQL 231 | # database: 232 | # adapter: mysql 233 | # database: some_database_with_users_table 234 | # username: root 235 | # password: 236 | # host: localhost 237 | # user_table: users 238 | # username_column: username 239 | # password_column: password 240 | # 241 | # When replying to a CAS client's validation request, the server will normally 242 | # provide the client with the authenticated user's username. However it is 243 | # possible for the server to provide the client with additional attributes. 244 | # You can configure the SQL authenticator to provide data from additional 245 | # columns in the users table by listing the names of the columns under the 246 | # 'extra_attributes' option. Note though that this functionality is experimental. 247 | # It should work with RubyCAS-Client, but may or may not work with other CAS 248 | # clients. 249 | # 250 | # For example, with this configuration, the 'full_name' and 'access_level' 251 | # columns will be provided to your CAS clients along with the username: 252 | # 253 | #authenticator: 254 | # class: CASServer::Authenticators::SQL 255 | # database: 256 | # adapter: mysql 257 | # database: some_database_with_users_table 258 | # user_table: users 259 | # username_column: username 260 | # password_column: password 261 | # extra_attributes: full_name, access_level 262 | # 263 | # 264 | # 265 | # === Google Authentication ==================================================== 266 | # 267 | # The Google authenticator allows users to log in to your CAS server using 268 | # their Google account credentials (i.e. the same email and password they 269 | # would use to log in to Google services like Gmail). This authenticator 270 | # requires no special configuration -- just specify its class name: 271 | # 272 | #authenticator: 273 | # class: CASServer::Authenticators::Google 274 | # 275 | # If you are behind an http proxy, you can try specifying proxy settings as follows: 276 | # 277 | #authenticator: 278 | # class: CASServer::Authenticators::Google 279 | # proxy: 280 | # host: your-proxy-server 281 | # port: 8080 282 | # username: nil 283 | # password: nil 284 | # 285 | # Note that as with all authenticators, it is possible to use the Google 286 | # authenticator alongside other authenticators. For example, CAS can first 287 | # attempt to validate the account with Google, and if that fails, fall back 288 | # to some other local authentication mechanism. 289 | # 290 | # For example: 291 | # 292 | #authenticator: 293 | # - class: CASServer::Authenticators::Google 294 | # - class: CASServer::Authenticators::SQL 295 | # database: 296 | # adapter: mysql 297 | # database: some_database_with_users_table 298 | # username: root 299 | # password: 300 | # host: localhost 301 | # user_table: user 302 | # username_column: username 303 | # password_column: password 304 | # 305 | # 306 | # === ActiveDirectory Authentication =========================================== 307 | # 308 | # This method authenticates against Microsoft's Active Directory using LDAP. 309 | # You must configure the ActiveDirectory server, and base DN. The port number 310 | # and LDAP filter are optional. You must also enter a CN and password 311 | # for a special "authenticator" user. This account is used to log in to 312 | # the ActiveDirectory server and search LDAP. This does not have to be an 313 | # administrative account -- it only has to be able to search for other 314 | # users. 315 | # 316 | # Note that the auth_user parameter must be the user's CN (Common Name). 317 | # In Active Directory, the CN is genarally the user's full name, which is usually 318 | # NOT the same as their username (sAMAccountName). 319 | # 320 | # For example: 321 | # 322 | #authenticator: 323 | # class: CASServer::Authenticators::ActiveDirectoryLDAP 324 | # ldap: 325 | # host: ad.example.net 326 | # port: 389 327 | # base: dc=example,dc=net 328 | # filter: (objectClass=person) 329 | # auth_user: authenticator 330 | # auth_password: itsasecret 331 | # 332 | # A more complicated example, where the authenticator will use TLS encryption, 333 | # will ignore users with disabled accounts, and will pass on the 'cn' and 'mail' 334 | # attributes to CAS clients: 335 | # 336 | #authenticator: 337 | # class: CASServer::Authenticators::ActiveDirectoryLDAP 338 | # ldap: 339 | # host: ad.example.net 340 | # port: 636 341 | # base: dc=example,dc=net 342 | # filter: (objectClass=person) & !(msExchHideFromAddressLists=TRUE) 343 | # auth_user: authenticator 344 | # auth_password: itsasecret 345 | # encryption: simple_tls 346 | # extra_attributes: cn, mail 347 | # 348 | # It is possible to authenticate against Active Directory without the 349 | # authenticator user, but this requires that users type in their CN as 350 | # the username rather than typing in their sAMAccountName. In other words 351 | # users will likely have to authenticate by typing their full name, 352 | # rather than their username. If you prefer to do this, then just 353 | # omit the auth_user and auth_password values in the above example. 354 | # 355 | # 356 | # === LDAP Authentication ====================================================== 357 | # 358 | # This is a more general version of the ActiveDirectory authenticator. 359 | # The configuration is similar, except you don't need an authenticator 360 | # username or password. The following example has been reported to work 361 | # for a basic OpenLDAP setup. 362 | # 363 | #authenticator: 364 | # class: CASServer::Authenticators::LDAP 365 | # ldap: 366 | # host: ldap.example.net 367 | # port: 389 368 | # base: dc=example,dc=net 369 | # username_attribute: uid 370 | # filter: (objectClass=person) 371 | # 372 | # If you need more secure connections via TSL, specify the 'encryption' 373 | # option and change the port. This example also forces the authenticator 374 | # to connect using a special "authenticator" user with the given 375 | # username and password (see the ActiveDirectoryLDAP authenticator 376 | # explanation above): 377 | # 378 | #authenticator: 379 | # class: CASServer::Authenticators::LDAP 380 | # ldap: 381 | # host: ldap.example.net 382 | # port: 636 383 | # base: dc=example,dc=net 384 | # filter: (objectClass=person) 385 | # encryption: simple_tls 386 | # auth_user: cn=admin,dc=example,dc=net 387 | # auth_password: secret 388 | # 389 | # If you need additional data about the user passed to the client (for example, 390 | # their 'cn' and 'mail' attributes, you can specify the list of attributes 391 | # under the extra_attributes config option: 392 | # 393 | #authenticator: 394 | # class: CASServer::Authenticators::LDAP 395 | # ldap: 396 | # host: ldap.example.net 397 | # port: 389 398 | # base: dc=example,dc=net 399 | # filter: (objectClass=person) 400 | # extra_attributes: cn, mail 401 | # 402 | # Note that the above functionality is somewhat limited by client compatibility. 403 | # See the SQL authenticator notes above for more info. 404 | # 405 | # 406 | # === Custom Authentication ==================================================== 407 | # 408 | # It should be relatively easy to write your own Authenticator class. Have a look 409 | # at the built-in authenticators in the casserver/authenticators directory. Your 410 | # authenticator should extend the CASServer::Authenticators::Base class and must 411 | # implement a validate() method that takes a single hash argument. When the user 412 | # submits the login form, the username and password they entered is passed to 413 | # validate() as a hash under :username and :password keys. In the future, this 414 | # hash might also contain other data such as the domain that the user is logging 415 | # in to. 416 | # 417 | # To use your custom authenticator, specify it's class name and path to the 418 | # source file in the authenticator section of the config. Any other parameters 419 | # you specify in the authenticator configuration will be passed on to the 420 | # authenticator and made availabe in the validate() method as an @options hash. 421 | # 422 | # Example: 423 | # 424 | #authenticator: 425 | # class: FooModule::MyCustomAuthenticator 426 | # source: /path/to/source.rb 427 | # option_a: foo 428 | # another_option: yeeha 429 | # 430 | # === Multiple Authenticators ================================================== 431 | # 432 | # If you need to have more than one source for authentication, such as an LDAP 433 | # directory and a database, you can use multiple authenticators by making 434 | # :authenticator an array of authenticators. 435 | # 436 | #authenticator: 437 | # - 438 | # class: CASServer::Authenticators::ActiveDirectoryLDAP 439 | # ldap: 440 | # host: ad.example.net 441 | # port: 389 442 | # base: dc=example,dc=net 443 | # filter: (objectClass=person) 444 | # - 445 | # class: CASServer::Authenticators::SQL 446 | # database: 447 | # adapter: mysql 448 | # database: some_database_with_users_table 449 | # username: root 450 | # password: 451 | # host: localhost 452 | # user_table: user 453 | # username_column: username 454 | # password_column: password 455 | # 456 | # During authentication, the user credentials will be checked against the first 457 | # authenticator and on failure fall through to the second authenticator. 458 | # 459 | 460 | 461 | ##### LOOK & FEEL ############################################################## 462 | 463 | # Set the path to the theme directory that determines how your CAS pages look. 464 | # 465 | # Custom themes are not well supported yet, but will be in the near future. In 466 | # the meantime, if you want to create a custom theme, you can create a 467 | # subdirectory under the CASServer's themes dir (for example, 468 | # '/usr/lib/ruby/1.8/gems/casserver-xxx/public/themes', if you installed CASServer 469 | # on Linux as a gem). A theme is basically just a theme.css file that overrides 470 | # the themes/cas.css styles along with a collection of image files 471 | # like logo.png and bg.png. 472 | # 473 | # By default, we use the 'simple' theme which you can find in themes/simple. 474 | theme: simple 475 | 476 | # The name of your company/organization. This will show up on the login page. 477 | organization: CAS 478 | 479 | # A short bit of text that shows up on the login page. You can make this blank 480 | # if you prefer to have no extra text shown at the bottom of the login box. 481 | infoline: Powered by RubyCAS-Server 482 | 483 | # Custom views directory. If set, this will be used instead of 'lib/casserver/views'. 484 | #custom_views: /path/to/custom/views 485 | 486 | # Custom public directory. If set, static content (css, etc.) will be served from here rather 487 | # than from rubycas-server's internal 'public' directory (but be mindful of any overriding 488 | # settings you may have in your web server's config). 489 | #public_dir: /path/to/custom/public 490 | 491 | ##### LOCALIZATION (L10N) ####################################################### 492 | # The server will attempt to detect the user's locale and show text in the 493 | # appropriate language based on: 494 | # 495 | # 1. The 'lang' URL parameter (if any) 496 | # 2. The 'lang' cookie (if any) 497 | # 3. The HTTP_ACCEPT_LANGUAGE header supplied by the user's browser. 498 | # 4. The HTTP_USER_AGENT header supplied by the user's browser. 499 | # 500 | # If the locale cannot be established based on one of the above checks (in the 501 | # shown order), then the below 'default_locale' option will be used. 502 | # 503 | # The format is the same as standard linux locales (langagecode_COUNTRYCODE): 504 | # 505 | # ru_RU - Russian, Russia 506 | # eo_AQ - Esperanto, Antarctica 507 | # 508 | # It will also work if you leave out the region (i.e. just "ru" for Russian, 509 | # "eo" for Esperanto). 510 | # 511 | # If you are interested in contributing new translations or have corrections 512 | # to the existing translations, see 513 | # http://code.google.com/p/rubycas-server/wiki/HowToContribueTranslations 514 | # 515 | default_locale: en 516 | 517 | ##### LOGGING ################################################################## 518 | 519 | # Configure general logging. This log is where you'll want to look in case of 520 | # problems. 521 | # 522 | # You may want to change the file to something like /var/log/casserver.log 523 | # Set the level to DEBUG if you want more detailed logging. 524 | 525 | log: 526 | file: /var/log/casserver.log 527 | level: INFO 528 | 529 | 530 | # If you want full database logging, uncomment this next section. 531 | # Every SQL query will be logged here. This is useful for debugging database 532 | # problems. 533 | 534 | #db_log: 535 | # file: /var/log/casserver_db.log 536 | 537 | 538 | # Setting the following option to true will disable CLI output to stdout. 539 | # i.e. this will get rid of messages like ">>> Redirecting RubyCAS-Server log..." 540 | # This is useful when, for example, you're running rspecs. 541 | 542 | #quiet: true 543 | 544 | 545 | ##### SINGLE SIGN-OUT ########################################################## 546 | 547 | # When a user logs in to a CAS-enabled client application, that application 548 | # generally opens its own local user session. When the user then logs out 549 | # through the CAS server, each of the CAS-enabled client applications need 550 | # to be notified so that they can close their own local sessions for that user. 551 | # 552 | # Up until recently this was not possible within CAS. However, a method for 553 | # performing this notification was recently added to the protocol (in CAS 3.1). 554 | # This works exactly as described above -- when the user logs out, the CAS 555 | # server individually contacts each client service and notifies it of the 556 | # logout. Currently not all client applications support this, so this 557 | # behaviour is disabled by default. To enable it, uncomment the following 558 | # configuration line. Note that currently it is not possible to enable 559 | # or disable single-sign-out on a per-service basis, but this functionality 560 | # is planned for a future release. 561 | 562 | #enable_single_sign_out: true 563 | 564 | 565 | ##### OTHER #################################################################### 566 | 567 | # You can set various ticket expiry times (specify the value in seconds). 568 | 569 | # Unused login and service tickets become unusable this many seconds after 570 | # they are created. (Defaults to 5 minutes) 571 | 572 | #maximum_unused_login_ticket_lifetime: 300 573 | #maximum_unused_service_ticket_lifetime: 300 574 | 575 | # The server must periodically delete old tickets (login tickets, service tickets 576 | # proxy-granting tickets, and ticket-granting tickets) to prevent buildup of 577 | # stale data. This effectively limits the maximum length of a CAS session to 578 | # the lifetime given here (in seconds). (Defaults to 48 hours) 579 | # 580 | # Note that this limit is not enforced on the client side; it refers only to the 581 | # the maximum lifetime of tickets on the CAS server. 582 | 583 | #maximum_session_lifetime: 172800 584 | 585 | 586 | # If you want the usernames entered on the login page to be automatically 587 | # downcased (converted to lowercase), enable the following option. When this 588 | # option is set to true, if the user enters "JSmith" as their username, the 589 | # system will automatically 590 | # convert this to "jsmith". 591 | 592 | #downcase_username: true 593 | -------------------------------------------------------------------------------- /config/unicorn.rb: -------------------------------------------------------------------------------- 1 | # Sample configuration file for Unicorn (not Rack) 2 | # 3 | # See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete 4 | # documentation. 5 | SINATRA_ROOT = `pwd`.strip 6 | 7 | # Use at least one worker per core if you're on a dedicated server, 8 | # more will usually help for _short_ waits on databases/caches. 9 | worker_processes 3 10 | 11 | # Help ensure your application will always spawn in the symlinked 12 | # "current" directory that Capistrano sets up. 13 | working_directory SINATRA_ROOT # available in 0.94.0+ 14 | 15 | # listen on both a Unix domain socket and a TCP port, 16 | # we use a shorter backlog for quicker failover when busy 17 | # listen "/tmp/.sock", :backlog => 64 18 | listen 18889, :tcp_nopush => true 19 | 20 | # nuke workers after 30 seconds instead of 60 seconds (the default) 21 | timeout 30 22 | 23 | # feel free to point this anywhere accessible on the filesystem 24 | 25 | pid "#{SINATRA_ROOT}/tmp/pids/unicorn.pid" 26 | 27 | # relative_path "/test_platform" 28 | # some applications/frameworks log to stderr or stdout, so prevent 29 | # them from going to /dev/null when daemonized here: 30 | stderr_path "#{SINATRA_ROOT}/log/unicorn.stderr.log" 31 | stdout_path "#{SINATRA_ROOT}/log/unicorn.stdout.log" 32 | 33 | # combine REE with "preload_app true" for memory savings 34 | # http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow 35 | preload_app false 36 | GC.respond_to?(:copy_on_write_friendly=) and 37 | GC.copy_on_write_friendly = true 38 | 39 | before_fork do |server, worker| 40 | # the following is highly recomended for Rails + "preload_app true" 41 | # as there's no need for the master process to hold a connection 42 | # defined?(ActiveRecord::Base) and 43 | # ActiveRecord::Base.connection.disconnect! 44 | 45 | # The following is only recommended for memory/DB-constrained 46 | # installations. It is not needed if your system can house 47 | # twice as many worker_processes as you have configured. 48 | # 49 | # # This allows a new master process to incrementally 50 | # # phase out the old master process with SIGTTOU to avoid a 51 | # # thundering herd (especially in the "preload_app false" case) 52 | # # when doing a transparent upgrade. The last worker spawned 53 | # # will then kill off the old master process with a SIGQUIT. 54 | old_pid = "#{server.config[:pid]}.oldbin" 55 | 56 | puts 'pid:' 57 | puts '-------------------' 58 | puts server.pid 59 | puts old_pid 60 | puts '---------------------' 61 | 62 | if old_pid != server.pid 63 | begin 64 | sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU 65 | Process.kill(sig, File.read(old_pid).to_i) 66 | rescue Errno::ENOENT, Errno::ESRCH 67 | end 68 | end 69 | # 70 | # # *optionally* throttle the master from forking too quickly by sleeping 71 | sleep 1 72 | end 73 | 74 | after_fork do |server, worker| 75 | # per-process listener ports for debugging/admin/migrations 76 | # addr = "127.0.0.1:#{9293 + worker.nr}" 77 | # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true) 78 | 79 | # the following is *required* for Rails + "preload_app true", 80 | # defined?(ActiveRecord::Base) and 81 | # ActiveRecord::Base.establish_connection 82 | 83 | # if preload_app is true, then you may also want to check and 84 | # restart any other shared sockets/descriptors such as Memcached, 85 | # and Redis. TokyoCabinet file handles are safe to reuse 86 | # between any number of forked children (assuming your kernel 87 | # correctly implements pread()/pwrite() system calls) 88 | end -------------------------------------------------------------------------------- /db/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/db/.gitignore -------------------------------------------------------------------------------- /db/migrate/001_create_initial_structure.rb: -------------------------------------------------------------------------------- 1 | class CreateInitialStructure < ActiveRecord::Migration 2 | def self.up 3 | # Oracle table names cannot exceed 30 chars... 4 | # See http://code.google.com/p/rubycas-server/issues/detail?id=15 5 | create_table 'casserver_lt', :force => true do |t| 6 | t.string 'ticket', :null => false 7 | t.timestamp 'created_on', :null => false 8 | t.datetime 'consumed', :null => true 9 | t.string 'client_hostname', :null => false 10 | end 11 | 12 | create_table 'casserver_st', :force => true do |t| 13 | t.string 'ticket', :null => false 14 | t.text 'service', :null => false 15 | t.timestamp 'created_on', :null => false 16 | t.datetime 'consumed', :null => true 17 | t.string 'client_hostname', :null => false 18 | t.string 'username', :null => false 19 | t.string 'type', :null => false 20 | t.integer 'granted_by_pgt_id', :null => true 21 | t.integer 'granted_by_tgt_id', :null => true 22 | end 23 | 24 | create_table 'casserver_tgt', :force => true do |t| 25 | t.string 'ticket', :null => false 26 | t.timestamp 'created_on', :null => false 27 | t.string 'client_hostname', :null => false 28 | t.string 'username', :null => false 29 | t.text 'extra_attributes', :null => true 30 | end 31 | 32 | create_table 'casserver_pgt', :force => true do |t| 33 | t.string 'ticket', :null => false 34 | t.timestamp 'created_on', :null => false 35 | t.string 'client_hostname', :null => false 36 | t.string 'iou', :null => false 37 | t.integer 'service_ticket_id', :null => false 38 | end 39 | end # self.up 40 | 41 | def self.down 42 | drop_table 'casserver_pgt' 43 | drop_table 'casserver_tgt' 44 | drop_table 'casserver_st' 45 | drop_table 'casserver_lt' 46 | end # self.down 47 | end 48 | -------------------------------------------------------------------------------- /lib/casserver.rb: -------------------------------------------------------------------------------- 1 | module CASServer; end 2 | 3 | require 'active_record' 4 | require 'active_support' 5 | require 'sinatra/base' 6 | require 'builder' # for XML views 7 | require 'logger' 8 | $LOG = Logger.new(STDOUT) 9 | 10 | require 'casserver/server' 11 | 12 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/active_directory_ldap.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/ldap' 2 | 3 | # Slightly modified version of the LDAP authenticator for Microsoft's ActiveDirectory. 4 | # The only difference is that the default_username_attribute for AD is 'sAMAccountName' 5 | # rather than 'uid'. 6 | class CASServer::Authenticators::ActiveDirectoryLDAP < CASServer::Authenticators::LDAP 7 | protected 8 | def default_username_attribute 9 | "sAMAccountName" 10 | end 11 | 12 | def extract_extra_attributes(ldap_entry) 13 | super(ldap_entry) 14 | if @extra_attributes["objectGUID"] 15 | @extra_attributes["guid"] = @extra_attributes["objectGUID"].to_s.unpack("H*").to_s 16 | end 17 | ldap_entry 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/active_resource.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/base' 2 | 3 | begin 4 | require 'active_resource' 5 | rescue LoadError 6 | require 'rubygems' 7 | begin 8 | gem 'activeresource', '~> 3.0.0' 9 | rescue Gem::LoadError 10 | $stderr.puts 11 | $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 12 | $stderr.puts 13 | $stderr.puts "To use the ActiveResource authenticator, you must first install the 'activeresource' gem." 14 | $stderr.puts 15 | $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 16 | exit 1 17 | end 18 | require 'active_resource' 19 | end 20 | 21 | module CASServer 22 | module Authenticators 23 | 24 | module Helpers 25 | class Identity < ActiveResource::Base 26 | 27 | # define method_name accessor 28 | cattr_accessor(:method_name) 29 | self.method_name = :authenticate 30 | 31 | def self.method_type 32 | @@method_type ||= :post 33 | end 34 | 35 | def self.method_type= type 36 | methods = [:get, :post, :put, :delete] 37 | raise ArgumentError, "Method type should be one of #{methods.map { |m| m.to_s.upcase }.join(', ')}" unless methods.include? type.to_sym 38 | @@method_type = type 39 | end 40 | 41 | # Autenticate an identity using the given method 42 | # @param [Hash] credentials 43 | def self.authenticate(credentials = {}) 44 | response = send(method_type, method_name, credentials) 45 | new.from_authentication_data(response) 46 | end 47 | 48 | # Used to load object attributes from the given response 49 | def from_authentication_data response 50 | load_attributes_from_response(response) 51 | end 52 | end 53 | end 54 | 55 | class ActiveResource < Base 56 | 57 | # This is called at server startup. 58 | # Any class-wide initializiation for the authenticator should be done here. 59 | # (e.g. establish database connection). 60 | # You can leave this empty if you don't need to set up anything. 61 | def self.setup(options) 62 | raise AuthenticatorError, 'You must define at least site option' unless options[:site] 63 | # apply options to active resource object 64 | options.each do |method, arg| 65 | Helpers::Identity.send "#{method}=", arg if Helpers::Identity.respond_to? "#{method}=" 66 | end 67 | $LOG.info "ActiveResource configuration loaded" 68 | end 69 | 70 | # Override this to implement your authentication credential validation. 71 | # This is called each time the user tries to log in. The credentials hash 72 | # holds the credentials as entered by the user (generally under :username 73 | # and :password keys; :service and :request are also included by default) 74 | # 75 | # Note that the standard credentials can be read in to instance variables 76 | # by calling #read_standard_credentials. 77 | def validate(credentials) 78 | begin 79 | $LOG.debug("Starting Active Resource authentication") 80 | result = Helpers::Identity.authenticate(credentials.except(:request)) 81 | extract_extra_attributes(result) if result 82 | !!result 83 | rescue ::ActiveResource::ConnectionError => e 84 | if e.response.blank? # band-aid for ARes 2.3.x -- craps out if to_s is called without a response 85 | e = e.class.to_s 86 | end 87 | $LOG.warn("Error during authentication: #{e}") 88 | false 89 | end 90 | end 91 | 92 | private 93 | 94 | def extract_extra_attributes(resource) 95 | @extra_attributes = {} 96 | $LOG.debug("Parsing extra attributes") 97 | if @options[:extra_attributes] 98 | extra_attributes_to_extract.each do |attr| 99 | @extra_attributes[attr] = resource.send(attr).to_s 100 | end 101 | else 102 | @extra_attributes = resource.attributes 103 | end 104 | # do filtering 105 | extra_attributes_to_filter.each do |attr| 106 | @extra_attributes.delete(attr) 107 | end 108 | end 109 | 110 | # extract attributes to filter from the given configuration 111 | def extra_attributes_to_filter 112 | # default value if not set 113 | return ['password'] unless @options[:filter_attributes] 114 | # parse option value 115 | if @options[:filter_attributes].kind_of? Array 116 | attrs = @options[:filter_attributes] 117 | elsif @options[:filter_attributes].kind_of? String 118 | attrs = @options[:filter_attributes].split(',').collect { |col| col.strip } 119 | else 120 | $LOG.error("Can't figure out attribute list from #{@options[:filter_attributes].inspect}. This must be an Aarray of column names or a comma-separated list.") 121 | attrs = [] 122 | end 123 | attrs 124 | end 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/authlogic_crypto_providers/aes256.rb: -------------------------------------------------------------------------------- 1 | require "openssl" 2 | 3 | module Authlogic 4 | module CryptoProviders 5 | # This encryption method is reversible if you have the supplied key. So in order to use this encryption method you must supply it with a key first. 6 | # In an initializer, or before your application initializes, you should do the following: 7 | # 8 | # Authlogic::CryptoProviders::AES256.key = "my really long and unique key, preferrably a bunch of random characters" 9 | # 10 | # My final comment is that this is a strong encryption method, but its main weakness is that its reversible. If you do not need to reverse the hash 11 | # then you should consider Sha512 or BCrypt instead. 12 | # 13 | # Keep your key in a safe place, some even say the key should be stored on a separate server. 14 | # This won't hurt performance because the only time it will try and access the key on the separate server is during initialization, which only 15 | # happens once. The reasoning behind this is if someone does compromise your server they won't have the key also. Basically, you don't want to 16 | # store the key with the lock. 17 | class AES256 18 | class << self 19 | attr_writer :key 20 | 21 | def encrypt(*tokens) 22 | aes.encrypt 23 | aes.key = @key 24 | [aes.update(tokens.join) + aes.final].pack("m").chomp 25 | end 26 | 27 | def matches?(crypted, *tokens) 28 | aes.decrypt 29 | aes.key = @key 30 | (aes.update(crypted.unpack("m").first) + aes.final) == tokens.join 31 | rescue OpenSSL::CipherError 32 | false 33 | end 34 | 35 | private 36 | def aes 37 | raise ArgumentError.new("You must provide a key like #{name}.key = my_key before using the #{name}") if @key.blank? 38 | @aes ||= OpenSSL::Cipher::Cipher.new("AES-256-ECB") 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/authlogic_crypto_providers/bcrypt.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require "bcrypt" 3 | rescue LoadError 4 | end 5 | 6 | module Authlogic 7 | module CryptoProviders 8 | # For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear launch codes you might want to consier BCrypt. This is an extremely 9 | # secure hashing algorithm, mainly because it is slow. A brute force attack on a BCrypt encrypted password would take much longer than a brute force attack on a 10 | # password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this, generating a password takes exponentially longer than any 11 | # of the Sha algorithms. I did some benchmarking to save you some time with your decision: 12 | # 13 | # require "bcrypt" 14 | # require "digest" 15 | # require "benchmark" 16 | # 17 | # Benchmark.bm(18) do |x| 18 | # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } } 19 | # x.report("BCrypt (cost = 2:") { 100.times { BCrypt::Password.create("mypass", :cost => 2) } } 20 | # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } } 21 | # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } } 22 | # end 23 | # 24 | # user system total real 25 | # BCrypt (cost = 10): 10.780000 0.060000 10.840000 ( 11.100289) 26 | # BCrypt (cost = 2): 0.180000 0.000000 0.180000 ( 0.181914) 27 | # Sha512: 0.000000 0.000000 0.000000 ( 0.000829) 28 | # Sha1: 0.000000 0.000000 0.000000 ( 0.000395) 29 | # 30 | # You can play around with the cost to get that perfect balance between performance and security. 31 | # 32 | # Decided BCrypt is for you? Just insall the bcrypt gem: 33 | # 34 | # gem install bcrypt-ruby 35 | # 36 | # Tell acts_as_authentic to use it: 37 | # 38 | # acts_as_authentic do |c| 39 | # c.crypto_provider = Authlogic::CryptoProviders::BCrypt 40 | # end 41 | # 42 | # You are good to go! 43 | class BCrypt 44 | class << self 45 | # This is the :cost option for the BCrpyt library. The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10. 46 | # Set this to whatever you want, play around with it to get that perfect balance between security and performance. 47 | def cost 48 | @cost ||= 10 49 | end 50 | attr_writer :cost 51 | 52 | # Creates a BCrypt hash for the password passed. 53 | def encrypt(*tokens) 54 | ::BCrypt::Password.create(join_tokens(tokens), :cost => cost) 55 | end 56 | 57 | # Does the hash match the tokens? Uses the same tokens that were used to encrypt. 58 | def matches?(hash, *tokens) 59 | $LOG.debug hash 60 | $LOG.debug tokens.inspect 61 | 62 | hash = new_from_hash(hash) 63 | return false if hash.blank? 64 | hash == join_tokens(tokens) 65 | end 66 | 67 | # This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost 68 | def cost_matches?(hash) 69 | hash = new_from_hash(hash) 70 | if hash.blank? 71 | false 72 | else 73 | hash.cost == cost 74 | end 75 | end 76 | 77 | private 78 | def join_tokens(tokens) 79 | tokens.flatten.join 80 | end 81 | 82 | def new_from_hash(hash) 83 | begin 84 | ::BCrypt::Password.new(hash) 85 | rescue ::BCrypt::Errors::InvalidHash 86 | return nil 87 | end 88 | end 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/authlogic_crypto_providers/md5.rb: -------------------------------------------------------------------------------- 1 | require "digest/md5" 2 | 3 | module Authlogic 4 | module CryptoProviders 5 | # This class was made for the users transitioning from md5 based systems. 6 | # I highly discourage using this crypto provider as it superbly inferior 7 | # to your other options. 8 | # 9 | # Please use any other provider offered by Authlogic. 10 | class MD5 11 | class << self 12 | attr_accessor :join_token 13 | 14 | # The number of times to loop through the encryption. 15 | def stretches 16 | @stretches ||= 1 17 | end 18 | attr_writer :stretches 19 | 20 | # Turns your raw password into a MD5 hash. 21 | def encrypt(*tokens) 22 | digest = tokens.flatten.join(join_token) 23 | stretches.times { digest = Digest::MD5.hexdigest(digest) } 24 | digest 25 | end 26 | 27 | # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt. 28 | def matches?(crypted, *tokens) 29 | encrypt(*tokens) == crypted 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/authlogic_crypto_providers/sha1.rb: -------------------------------------------------------------------------------- 1 | require "digest/sha1" 2 | 3 | module Authlogic 4 | module CryptoProviders 5 | # This class was made for the users transitioning from restful_authentication. 6 | # I highly discourage using this crypto provider as it inferior to your other options. 7 | # Please use any other provider offered by Authlogic. 8 | class Sha1 9 | class << self 10 | def join_token 11 | @join_token ||= "--" 12 | end 13 | attr_writer :join_token 14 | 15 | def digest_format=(format) 16 | @digest_format = format 17 | end 18 | 19 | # This is for "old style" authentication with a custom format of digest 20 | def digest(tokens) 21 | if @digest_format 22 | @digest_format. 23 | gsub('PASSWORD', tokens.first). 24 | gsub('SALT', tokens.last) 25 | else 26 | tokens.join(join_token) 27 | end 28 | end 29 | 30 | # The number of times to loop through the encryption. 31 | # This is ten because that is what restful_authentication defaults to. 32 | 33 | def stretches 34 | @stretches ||= 10 35 | end 36 | attr_writer :stretches 37 | 38 | # Turns your raw password into a Sha1 hash. 39 | def encrypt(*tokens) 40 | tokens = tokens.flatten 41 | 42 | if stretches > 1 43 | hash = tokens.shift 44 | stretches.times { hash = Digest::SHA1.hexdigest([hash, *tokens].join(join_token)) } 45 | else 46 | hash = Digest::SHA1.hexdigest( digest(tokens) ) 47 | end 48 | 49 | hash 50 | end 51 | 52 | # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt. 53 | def matches?(crypted, *tokens) 54 | encrypt(*tokens) == crypted 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/authlogic_crypto_providers/sha512.rb: -------------------------------------------------------------------------------- 1 | require "digest/sha2" 2 | 3 | module Authlogic 4 | # The acts_as_authentic method has a crypto_provider option. This allows you to use any type of encryption you like. 5 | # Just create a class with a class level encrypt and matches? method. See example below. 6 | # 7 | # === Example 8 | # 9 | # class MyAwesomeEncryptionMethod 10 | # def self.encrypt(*tokens) 11 | # # the tokens passed will be an array of objects, what type of object is irrelevant, 12 | # # just do what you need to do with them and return a single encrypted string. 13 | # # for example, you will most likely join all of the objects into a single string and then encrypt that string 14 | # end 15 | # 16 | # def self.matches?(crypted, *tokens) 17 | # # return true if the crypted string matches the tokens. 18 | # # depending on your algorithm you might decrypt the string then compare it to the token, or you might 19 | # # encrypt the tokens and make sure it matches the crypted string, its up to you 20 | # end 21 | # end 22 | module CryptoProviders 23 | # = Sha512 24 | # 25 | # Uses the Sha512 hash algorithm to encrypt passwords. 26 | class Sha512 27 | class << self 28 | attr_accessor :join_token 29 | 30 | # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to. 31 | def stretches 32 | @stretches ||= 20 33 | end 34 | attr_writer :stretches 35 | 36 | # Turns your raw password into a Sha512 hash. 37 | def encrypt(*tokens) 38 | digest = tokens.flatten.join(join_token) 39 | stretches.times { digest = Digest::SHA512.hexdigest(digest) } 40 | digest 41 | end 42 | 43 | # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt. 44 | def matches?(crypted, *tokens) 45 | encrypt(*tokens) == crypted 46 | end 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/base.rb: -------------------------------------------------------------------------------- 1 | module CASServer 2 | module Authenticators 3 | class Base 4 | attr_accessor :options 5 | attr_reader :username # make this accessible so that we can pick up any 6 | # transformations done within the authenticator 7 | 8 | # This is called at server startup. 9 | # Any class-wide initializiation for the authenticator should be done here. 10 | # (e.g. establish database connection). 11 | # You can leave this empty if you don't need to set up anything. 12 | def self.setup(options) 13 | end 14 | 15 | # This is called prior to #validate (i.e. each time the user tries to log in). 16 | # Any per-instance initialization for the authenticator should be done here. 17 | # 18 | # By default this makes the authenticator options hash available for #validate 19 | # under @options and initializes @extra_attributes to an empty hash. 20 | def configure(options) 21 | raise ArgumentError, "options must be a HashWithIndifferentAccess" unless options.kind_of? HashWithIndifferentAccess 22 | @options = options.dup 23 | @extra_attributes = {} 24 | end 25 | 26 | # Override this to implement your authentication credential validation. 27 | # This is called each time the user tries to log in. The credentials hash 28 | # holds the credentials as entered by the user (generally under :username 29 | # and :password keys; :service and :request are also included by default) 30 | # 31 | # Note that the standard credentials can be read in to instance variables 32 | # by calling #read_standard_credentials. 33 | def validate(credentials) 34 | raise NotImplementedError, "This method must be implemented by a class extending #{self.class}" 35 | end 36 | 37 | def extra_attributes 38 | @extra_attributes 39 | end 40 | 41 | protected 42 | def read_standard_credentials(credentials) 43 | @username = credentials[:username] 44 | @password = credentials[:password] 45 | @service = credentials[:service] 46 | @request = credentials[:request] 47 | end 48 | 49 | def extra_attributes_to_extract 50 | if @options[:extra_attributes].kind_of? Array 51 | attrs = @options[:extra_attributes] 52 | elsif @options[:extra_attributes].kind_of? String 53 | attrs = @options[:extra_attributes].split(',').collect{|col| col.strip} 54 | else 55 | $LOG.error("Can't figure out attribute list from #{@options[:extra_attributes].inspect}. This must be an Aarray of column names or a comma-separated list.") 56 | attrs = [] 57 | end 58 | 59 | $LOG.debug("#{self.class.name} will try to extract the following extra_attributes: #{attrs.inspect}") 60 | return attrs 61 | end 62 | end 63 | end 64 | 65 | class AuthenticatorError < Exception 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/client_certificate.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/base' 2 | 3 | # NOT YET IMPLEMENTED 4 | # 5 | # This authenticator will authenticate the user based on a client SSL certificate. 6 | # 7 | # You will probably want to use this along with another authenticator, chaining 8 | # it so that if the client does not provide a certificate, the server can 9 | # fall back to some other authentication mechanism. 10 | # 11 | # Here's an example of how to use two chained authenticators in the config.yml 12 | # file. The server will first use the ClientCertificate authenticator, and 13 | # only fall back to the SQL authenticator of the first one fails: 14 | # 15 | # authenticator: 16 | # - 17 | # class: CASServer::Authenticators::ClientCertificate 18 | # - 19 | # class: CASServer::Authenticators::SQL 20 | # database: 21 | # adapter: mysql 22 | # database: some_database_with_users_table 23 | # user: root 24 | # password: 25 | # server: localhost 26 | # user_table: user 27 | # username_column: username 28 | # password_column: password 29 | # 30 | class CASServer::Authenticators::ClientCertificate < CASServer::Authenticators::Base 31 | def validate(credentials) 32 | read_standard_credentials(credentials) 33 | 34 | @client_cert = credentials[:request]['SSL_CLIENT_CERT'] 35 | 36 | # note that I haven't actually tested to see if SSL_CLIENT_CERT gets 37 | # filled with data when a client cert is provided, but this should be 38 | # the case at least in theory :) 39 | 40 | return false if @client_cert.blank? 41 | 42 | # IMPLEMENT SSL CERTIFICATE VALIDATION CODE HERE 43 | raise NotImplementedError, "#{self.class.name}#validate NOT YET IMPLEMENTED!" 44 | 45 | return true # if SSL certificate is valid, false otherwise 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/google.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/base' 2 | require 'uri' 3 | require 'net/http' 4 | require 'net/https' 5 | require 'timeout' 6 | 7 | # Validates Google accounts against Google's authentication service -- in other 8 | # words, this authenticator allows users to log in to CAS using their 9 | # Gmail/Google accounts. 10 | class CASServer::Authenticators::Google < CASServer::Authenticators::Base 11 | def validate(credentials) 12 | read_standard_credentials(credentials) 13 | 14 | return false if @username.blank? || @password.blank? 15 | 16 | auth_data = { 17 | 'Email' => @username, 18 | 'Passwd' => @password, 19 | 'service' => 'xapi', 20 | 'source' => 'RubyCAS-Server', 21 | 'accountType' => 'HOSTED_OR_GOOGLE' 22 | } 23 | 24 | url = URI.parse('https://www.google.com/accounts/ClientLogin') 25 | if @options[:proxy] 26 | http = Net::HTTP.Proxy(@options[:proxy][:host], @options[:proxy][:port], @options[:proxy][:username], @options[:proxy][:password]).new(url.host, url.port) 27 | else 28 | http = Net::HTTP.new(url.host, url.port) 29 | end 30 | http.use_ssl = true 31 | 32 | # TODO: make the timeout configurable 33 | wait_seconds = 10 34 | begin 35 | timeout(wait_seconds) do 36 | res = http.start do |conn| 37 | req = Net::HTTP::Post.new(url.path) 38 | req.set_form_data(auth_data,'&') 39 | conn.request(req) 40 | end 41 | 42 | case res 43 | when Net::HTTPSuccess 44 | true 45 | when Net::HTTPForbidden 46 | false 47 | else 48 | $LOG.error("Unexpected response from Google while validating credentials: #{res.inspect} ==> #{res.body}.") 49 | raise CASServer::AuthenticatorError, "Unexpected response received from Google while validating credentials." 50 | end 51 | end 52 | rescue Timeout::Error 53 | $LOG.error("Google did not respond to the credential validation request. We waited for #{wait_seconds.inspect} seconds before giving up.") 54 | raise CASServer::AuthenticatorError, "Timeout while waiting for Google to validate credentials." 55 | end 56 | 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/ldap.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/base' 2 | 3 | begin 4 | require 'net/ldap' 5 | rescue LoadError 6 | require 'rubygems' 7 | begin 8 | gem 'net-ldap', '~> 0.1.1' 9 | rescue Gem::LoadError 10 | $stderr.puts 11 | $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 12 | $stderr.puts 13 | $stderr.puts "To use the LDAP/AD authenticator, you must first install the 'net-ldap' gem." 14 | $stderr.puts " See http://github.com/RoryO/ruby-net-ldap for details." 15 | $stderr.puts 16 | $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 17 | exit 1 18 | end 19 | require 'net/ldap' 20 | end 21 | 22 | # Basic LDAP authenticator. Should be compatible with OpenLDAP and other similar LDAP servers, 23 | # although it hasn't been officially tested. See example config file for details on how 24 | # to configure it. 25 | class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base 26 | def validate(credentials) 27 | read_standard_credentials(credentials) 28 | 29 | return false if @password.blank? 30 | 31 | raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options 32 | raise CASServer::AuthenticatorError, "Invalid LDAP authenticator configuration!" unless @options[:ldap] 33 | raise CASServer::AuthenticatorError, "You must specify a server host in the LDAP configuration!" unless @options[:ldap][:host] || @options[:ldap][:server] 34 | 35 | raise CASServer::AuthenticatorError, "The username '#{@username}' contains invalid characters." if (@username =~ /[*\(\)\0\/]/) 36 | 37 | preprocess_username 38 | 39 | @ldap = Net::LDAP.new 40 | 41 | 42 | @options[:ldap][:host] ||= @options[:ldap][:server] 43 | @ldap.host = @options[:ldap][:host] 44 | @ldap.port = @options[:ldap][:port] if @options[:ldap][:port] 45 | @ldap.encryption(@options[:ldap][:encryption].intern) if @options[:ldap][:encryption] 46 | 47 | begin 48 | if @options[:ldap][:auth_user] 49 | bind_success = bind_by_username_with_preauthentication 50 | else 51 | bind_success = bind_by_username 52 | end 53 | 54 | return false unless bind_success 55 | 56 | entry = find_user 57 | extract_extra_attributes(entry) 58 | 59 | return true 60 | rescue Net::LDAP::LdapError => e 61 | raise CASServer::AuthenticatorError, 62 | "LDAP authentication failed with '#{e}'. Check your authenticator configuration." 63 | end 64 | end 65 | 66 | protected 67 | def default_username_attribute 68 | "cn" 69 | end 70 | 71 | private 72 | # Add prefix to username, if :username_prefix was specified in the :ldap config. 73 | def preprocess_username 74 | @username = @options[:ldap][:username_prefix] + @username if @options[:ldap][:username_prefix] 75 | end 76 | 77 | # Attempt to bind with the LDAP server using the username and password entered by 78 | # the user. If a :filter was specified in the :ldap config, the filter will be 79 | # added to the LDAP query for the username. 80 | def bind_by_username 81 | username_attribute = options[:ldap][:username_attribute] || default_username_attribute 82 | 83 | @ldap.bind_as(:base => @options[:ldap][:base], :password => @password, :filter => user_filter) 84 | end 85 | 86 | # If an auth_user is specified, we will connect ("pre-authenticate") with the 87 | # LDAP server using the authenticator account, and then attempt to bind as the 88 | # user who is actually trying to authenticate. Note that you need to set up 89 | # the special authenticator account first. Also, auth_user must be the authenticator 90 | # user's full CN, which is probably not the same as their username. 91 | # 92 | # This pre-authentication process is necessary because binding can only be done 93 | # using the CN, so having just the username is not enough. We connect as auth_user, 94 | # and then try to find the target user's CN based on the given username. Then we bind 95 | # as the target user to validate their credentials. 96 | def bind_by_username_with_preauthentication 97 | raise CASServer::AuthenticatorError, "A password must be specified in the configuration for the authenticator user!" unless 98 | @options[:ldap][:auth_password] 99 | 100 | @ldap.authenticate(@options[:ldap][:auth_user], @options[:ldap][:auth_password]) 101 | 102 | @ldap.bind_as(:base => @options[:ldap][:base], :password => @password, :filter => user_filter) 103 | end 104 | 105 | # Combine the filter for finding the user with the optional extra filter specified in the config 106 | # (if any). 107 | def user_filter 108 | username_attribute = options[:ldap][:username_attribute] || default_username_attribute 109 | 110 | filter = Array(username_attribute).map { |ua| Net::LDAP::Filter.eq(ua, @username) }.reduce(:|) 111 | unless @options[:ldap][:filter].blank? 112 | filter &= Net::LDAP::Filter.construct(@options[:ldap][:filter]) 113 | end 114 | 115 | filter 116 | end 117 | 118 | # Finds the user based on the user_filter (this is called after authentication). 119 | # We do this to make it possible to extract extra_attributes. 120 | def find_user 121 | results = @ldap.search( :base => options[:ldap][:base], :filter => user_filter) 122 | return results.first 123 | end 124 | 125 | def extract_extra_attributes(ldap_entry) 126 | @extra_attributes = {} 127 | extra_attributes_to_extract.each do |attr| 128 | v = ldap_entry[attr] 129 | next if !v || (v.respond_to?(:empty?) && v.empty?) 130 | if v.kind_of?(Array) 131 | @extra_attributes[attr] = [] 132 | ldap_entry[attr].each do |a| 133 | @extra_attributes[attr] << a.to_s 134 | end 135 | else 136 | @extra_attributes[attr] = v.to_s 137 | end 138 | end 139 | 140 | if @extra_attributes.empty? 141 | $LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.") 142 | else 143 | $LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}") 144 | end 145 | ldap_entry 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/ntlm.rb: -------------------------------------------------------------------------------- 1 | # THIS AUTHENTICATOR DOES NOT WORK (not even close!) 2 | # 3 | # I started working on this but run into a wall, so I am commiting what I've got 4 | # done and leaving it here with hopes of one day finishing it. 5 | # 6 | # The main problem is that although I've got the Lan Manager/NTLM password hash, 7 | # I'm not sure what to do with it. i.e. I need to check it against the AD or SMB 8 | # server or something... maybe faking an SMB share connection and using the LM 9 | # response for authentication might do the trick? 10 | 11 | require 'casserver/authenticators/base' 12 | 13 | # Ruby/NTLM package from RubyForge 14 | require 'net/ntlm' 15 | 16 | module CASServer 17 | module Authenticators 18 | class NTLM 19 | # This will have to be somehow called by the top of the 'get' method 20 | # in the Login controller (maybe via a hook?)... if this code fails 21 | # then the controller should fall back to some other method of authentication 22 | # (probably AD/LDAP or something). 23 | def filter_for_top_of_login_get_controller_method 24 | $LOG.debug @env.inspect 25 | if @env['HTTP_AUTHORIZATION'] =~ /NTLM ([^\s]+)/ 26 | # if we're here, then the client has sent back a Type1 or Type3 message 27 | # in reply to our NTLM challenge or our Type2 message 28 | data_raw = Base64.decode64($~[1]) 29 | $LOG.debug "T1 RAW: #{t1_raw}" 30 | t = Net::NTLM::Message::Message.parse(t1_raw) 31 | if t.kind_of? Net::NTLM::Type1 32 | t1 = t 33 | elsif t.kind_of? Net::NTLM::Type3 34 | t3 = t 35 | else 36 | raise "Invalid NTLM reply from client." 37 | end 38 | 39 | if t1 40 | $LOG.debug "T1: #{t1.inspect}" 41 | 42 | # now put together a Type2 message asking for the client to send 43 | # back NTLM credentials (LM hash and such) 44 | t2 = Net::NTLM::Message::Type2.new 45 | t2.set_flag :UNICODE 46 | t2.set_flag :NTLM 47 | t2.context = 0x0000000000000000 # this can probably just be left unassigned 48 | t2.challenge = 0x0123456789abcdef # this should be a random 8-byte integer 49 | 50 | $LOG.debug "T2: #{t2.inspect}" 51 | $LOG.debug "T2: #{t2.serialize}" 52 | headers["WWW-Authenticate"] = "NTLM #{t2.encode64}" 53 | 54 | # the client should respond to this with a Type3 message... 55 | r('401', '', headers) 56 | return 57 | else 58 | # NOTE: for some reason the server never receives the T3 response, even though monitoring 59 | # the HTTP traffic I can see that the client does send it back... there's probably 60 | # another bug hiding somewhere here 61 | 62 | lm_response = t3.lm_response 63 | ntlm_response = t3.ntlm_response 64 | username = t3.user 65 | # this is where we run up against a wall... we need some way to check the lm and/or ntlm 66 | # reponse against the authentication server (probably Active Directory)... maybe a samba 67 | # call would do it? 68 | $LOG.debug "T3 LM: #{lm_response.inspect}" 69 | $LOG.debug "T3 NTLM: #{ntlm_response.inspect}" 70 | 71 | # assuming the authentication was successful, we'll now need to do something in the 72 | # controller acting as if we'd received correct login credentials (i.e. proceed as if 73 | # CAS authentication was successful).... if authentication failed, then we should 74 | # just fall back to old-school web-based authentication, asking the user to enter 75 | # their username and password the normal CAS way 76 | end 77 | else 78 | # this sends the initial NTLM challenge, asking the browser 79 | # to send back a Type1 message 80 | headers['WWW-Authenticate'] = "NTLM" 81 | headers['Connection'] = "Close" 82 | r('401', '', headers) 83 | return 84 | end 85 | end 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/open_id.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/base' 2 | 3 | require 'openid' 4 | require 'openid/extensions/sreg' 5 | require 'openid/extensions/pape' 6 | require 'openid/store/memory' 7 | 8 | 9 | # CURRENTLY UNIMPLEMENTED 10 | # This is just starter code. 11 | class CASServer::Authenticators::OpenID < CASServer::Authenticators::Base 12 | 13 | def validate(credentials) 14 | raise NotImplementedError, "The OpenID authenticator is not yet implemented. "+ 15 | "See http://code.google.com/p/rubycas-server/issues/detail?id=36 if you are interested in helping this along." 16 | 17 | read_standard_credentials(credentials) 18 | 19 | store = OpenID::Store::Memory.new 20 | consumer = OpenID::Consumer.new({}, store) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/sql.rb: -------------------------------------------------------------------------------- 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 | # Authenticates against a plain SQL table. 11 | # 12 | # This assumes that all of your users are stored in a table that has a 'username' 13 | # column and a 'password' column. When the user logs in, CAS conects to the 14 | # database and looks for a matching username/password in the users table. If a 15 | # matching username and password is found, authentication is successful. 16 | # 17 | # Any database backend supported by ActiveRecord can be used. 18 | # 19 | # Config example: 20 | # 21 | # authenticator: 22 | # class: CASServer::Authenticators::SQL 23 | # database: 24 | # adapter: mysql 25 | # database: some_database_with_users_table 26 | # username: root 27 | # password: 28 | # server: localhost 29 | # user_table: users 30 | # username_column: username 31 | # password_column: password 32 | # 33 | # When replying to a CAS client's validation request, the server will normally 34 | # provide the client with the authenticated user's username. However it is now 35 | # possible for the server to provide the client with additional attributes. 36 | # You can configure the SQL authenticator to provide data from additional 37 | # columns in the users table by listing the names of the columns under the 38 | # 'extra_attributes' option. Note though that this functionality is experimental. 39 | # It should work with RubyCAS-Client, but may or may not work with other CAS 40 | # clients. 41 | # 42 | # For example, with this configuration, the 'full_name' and 'access_level' 43 | # columns will be provided to your CAS clients along with the username: 44 | # 45 | # authenticator: 46 | # class: CASServer::Authenticators::SQL 47 | # database: 48 | # adapter: mysql 49 | # database: some_database_with_users_table 50 | # user_table: users 51 | # username_column: username 52 | # password_column: password 53 | # ignore_type_column: true # indicates if you want to ignore Single Table Inheritance 'type' field 54 | # extra_attributes: full_name, access_level 55 | # 56 | class CASServer::Authenticators::SQL < CASServer::Authenticators::Base 57 | def self.setup(options) 58 | raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless options[:database] 59 | 60 | user_model_name = "CASUser_#{options[:auth_index]}" 61 | $LOG.debug "CREATING USER MODEL #{user_model_name}" 62 | 63 | class_eval %{ 64 | class #{user_model_name} < ActiveRecord::Base 65 | end 66 | } 67 | 68 | @user_model = const_get(user_model_name) 69 | @user_model.establish_connection(options[:database]) 70 | @user_model.set_table_name(options[:user_table] || 'users') 71 | @user_model.inheritance_column = 'no_inheritance_column' if options[:ignore_type_column] 72 | end 73 | 74 | def self.user_model 75 | @user_model 76 | end 77 | 78 | def validate(credentials) 79 | read_standard_credentials(credentials) 80 | raise_if_not_configured 81 | 82 | user_model = self.class.user_model 83 | 84 | username_column = @options[:username_column] || 'username' 85 | password_column = @options[:password_column] || 'password' 86 | 87 | $LOG.debug "#{self.class}: [#{user_model}] " + "Connection pool size: #{user_model.connection_pool.instance_variable_get(:@checked_out).length}/#{user_model.connection_pool.instance_variable_get(:@connections).length}" 88 | results = user_model.find(:all, :conditions => ["#{username_column} = ? AND #{password_column} = ?", @username, @password]) 89 | user_model.connection_pool.checkin(user_model.connection) 90 | 91 | if results.size > 0 92 | $LOG.warn("#{self.class}: Multiple matches found for user #{@username.inspect}") if results.size > 1 93 | 94 | unless @options[:extra_attributes].blank? 95 | if results.size > 1 96 | $LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}") 97 | else 98 | user = results.first 99 | 100 | extract_extra(user) 101 | log_extra 102 | end 103 | end 104 | 105 | return true 106 | else 107 | return false 108 | end 109 | end 110 | 111 | protected 112 | 113 | def raise_if_not_configured 114 | raise CASServer::AuthenticatorError.new( 115 | "Cannot validate credentials because the authenticator hasn't yet been configured" 116 | ) unless @options 117 | end 118 | 119 | def extract_extra user 120 | @extra_attributes = {} 121 | extra_attributes_to_extract.each do |col| 122 | @extra_attributes[col] = user.send(col) 123 | end 124 | end 125 | 126 | def log_extra 127 | if @extra_attributes.empty? 128 | $LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.") 129 | else 130 | $LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}") 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/sql_authlogic.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/sql' 2 | 3 | # These were pulled directly from Authlogic, and new ones can be added 4 | # just by including new Crypto Providers 5 | require File.dirname(__FILE__) + '/authlogic_crypto_providers/aes256' 6 | require File.dirname(__FILE__) + '/authlogic_crypto_providers/bcrypt' 7 | require File.dirname(__FILE__) + '/authlogic_crypto_providers/md5' 8 | require File.dirname(__FILE__) + '/authlogic_crypto_providers/sha1' 9 | require File.dirname(__FILE__) + '/authlogic_crypto_providers/sha512' 10 | 11 | begin 12 | require 'active_record' 13 | rescue LoadError 14 | require 'rubygems' 15 | require 'active_record' 16 | end 17 | 18 | # This is a version of the SQL authenticator that works nicely with Authlogic. 19 | # Passwords are encrypted the same way as it done in Authlogic. 20 | # Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in 21 | # config. 22 | # 23 | # Using this authenticator requires restful authentication plugin on rails (client) side. 24 | # 25 | # * git://github.com/binarylogic/authlogic.git 26 | # 27 | # Usage: 28 | 29 | # authenticator: 30 | # class: CASServer::Authenticators::SQLAuthlogic 31 | # database: 32 | # adapter: mysql 33 | # database: some_database_with_users_table 34 | # user: root 35 | # password: 36 | # server: localhost 37 | # user_table: user 38 | # username_column: login 39 | # password_column: crypted_password 40 | # salt_column: password_salt 41 | # encryptor: Sha1 42 | # encryptor_options: 43 | # digest_format: --SALT--PASSWORD-- 44 | # stretches: 1 45 | # 46 | class CASServer::Authenticators::SQLAuthlogic < CASServer::Authenticators::SQL 47 | 48 | def validate(credentials) 49 | read_standard_credentials(credentials) 50 | raise_if_not_configured 51 | 52 | user_model = self.class.user_model 53 | 54 | username_column = @options[:username_column] || "login" 55 | password_column = @options[:password_column] || "crypted_password" 56 | salt_column = @options[:salt_column] 57 | 58 | $LOG.debug "#{self.class}: [#{user_model}] " + "Connection pool size: #{user_model.connection_pool.instance_variable_get(:@checked_out).length}/#{user_model.connection_pool.instance_variable_get(:@connections).length}" 59 | results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username]) 60 | user_model.connection_pool.checkin(user_model.connection) 61 | 62 | begin 63 | encryptor = eval("Authlogic::CryptoProviders::" + @options[:encryptor] || "Sha512") 64 | rescue 65 | $LOG.warn("Could not initialize Authlogic crypto class for '#{@options[:encryptor]}'") 66 | encryptor = Authlogic::CryptoProviders::Sha512 67 | end 68 | 69 | @options[:encryptor_options].each do |name, value| 70 | encryptor.send("#{name}=", value) if encryptor.respond_to?("#{name}=") 71 | end 72 | 73 | if results.size > 0 74 | $LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1 75 | user = results.first 76 | tokens = [@password, (not salt_column.nil?) && user.send(salt_column) || nil].compact 77 | crypted = user.send(password_column) 78 | 79 | unless @options[:extra_attributes].blank? 80 | if results.size > 1 81 | $LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}") 82 | else 83 | extract_extra(user) 84 | log_extra 85 | end 86 | end 87 | 88 | return encryptor.matches?(crypted, tokens) 89 | else 90 | return false 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/sql_encrypted.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/sql' 2 | 3 | require 'digest/sha1' 4 | require 'digest/sha2' 5 | require 'crypt-isaac' 6 | 7 | # This is a more secure version of the SQL authenticator. Passwords are encrypted 8 | # rather than being stored in plain text. 9 | # 10 | # Based on code contributed by Ben Mabey. 11 | # 12 | # Using this authenticator requires some configuration on the client side. Please see 13 | # http://code.google.com/p/rubycas-server/wiki/UsingTheSQLEncryptedAuthenticator 14 | class CASServer::Authenticators::SQLEncrypted < CASServer::Authenticators::SQL 15 | # Include this module into your application's user model. 16 | # 17 | # Your model must have an 'encrypted_password' column where the password will be stored, 18 | # and an 'encryption_salt' column that will be populated with a random string before 19 | # the user record is first created. 20 | module EncryptedPassword 21 | def self.included(mod) 22 | raise "#{self} should be inclued in an ActiveRecord class!" unless mod.respond_to?(:before_save) 23 | mod.before_save :generate_encryption_salt 24 | end 25 | 26 | def encrypt(str) 27 | generate_encryption_salt unless encryption_salt 28 | Digest::SHA256.hexdigest("#{encryption_salt}::#{str}") 29 | end 30 | 31 | def password=(password) 32 | self[:encrypted_password] = encrypt(password) 33 | end 34 | 35 | def generate_encryption_salt 36 | self.encryption_salt = Digest::SHA1.hexdigest(Crypt::ISAAC.new.rand(2**31).to_s) unless 37 | encryption_salt 38 | end 39 | end 40 | 41 | def self.setup(options) 42 | super(options) 43 | user_model.__send__(:include, EncryptedPassword) 44 | end 45 | 46 | def validate(credentials) 47 | read_standard_credentials(credentials) 48 | raise_if_not_configured 49 | 50 | user_model = self.class.user_model 51 | 52 | username_column = @options[:username_column] || "username" 53 | encrypt_function = @options[:encrypt_function] || 'user.encrypted_password == Digest::SHA256.hexdigest("#{user.encryption_salt}::#{@password}")' 54 | 55 | $LOG.debug "#{self.class}: [#{user_model}] " + "Connection pool size: #{user_model.connection_pool.instance_variable_get(:@checked_out).length}/#{user_model.connection_pool.instance_variable_get(:@connections).length}" 56 | results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username]) 57 | user_model.connection_pool.checkin(user_model.connection) 58 | 59 | if results.size > 0 60 | $LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1 61 | user = results.first 62 | unless @options[:extra_attributes].blank? 63 | if results.size > 1 64 | $LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}") 65 | else 66 | extract_extra(user) 67 | log_extra 68 | end 69 | end 70 | return eval(encrypt_function) 71 | else 72 | return false 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/sql_md5.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/sql' 2 | 3 | require 'digest/md5' 4 | 5 | # Essentially the same as the standard SQL authenticator, but this version 6 | # assumes that your password is stored as an MD5 hash. 7 | # 8 | # This was contributed by malcomm for Drupal authentication. To work with 9 | # Drupal, you should use 'name' for the :username_column config option, and 10 | # 'pass' for the :password_column. 11 | class CASServer::Authenticators::SQLMd5 < CASServer::Authenticators::SQL 12 | 13 | protected 14 | def read_standard_credentials(credentials) 15 | super 16 | @password = Digest::MD5.hexdigest(@password) 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/sql_rest_auth.rb: -------------------------------------------------------------------------------- 1 | require 'casserver/authenticators/sql_encrypted' 2 | 3 | require 'digest/sha1' 4 | 5 | begin 6 | require 'active_record' 7 | rescue LoadError 8 | require 'rubygems' 9 | require 'active_record' 10 | end 11 | 12 | # This is a version of the SQL authenticator that works nicely with RestfulAuthentication. 13 | # Passwords are encrypted the same way as it done in RestfulAuthentication. 14 | # Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in 15 | # config. 16 | # 17 | # Using this authenticator requires restful authentication plugin on rails (client) side. 18 | # 19 | # * git://github.com/technoweenie/restful-authentication.git 20 | # 21 | class CASServer::Authenticators::SQLRestAuth < CASServer::Authenticators::SQLEncrypted 22 | 23 | def validate(credentials) 24 | read_standard_credentials(credentials) 25 | raise_if_not_configured 26 | 27 | raise CASServer::AuthenticatorError, "You must specify a 'site_key' in the SQLRestAuth authenticator's configuration!" unless @options[:site_key] 28 | raise CASServer::AuthenticatorError, "You must specify 'digest_streches' in the SQLRestAuth authenticator's configuration!" unless @options[:digest_streches] 29 | 30 | user_model = self.class.user_model 31 | 32 | username_column = @options[:username_column] || "email" 33 | 34 | $LOG.debug "#{self.class}: [#{user_model}] " + "Connection pool size: #{user_model.connection_pool.instance_variable_get(:@checked_out).length}/#{user_model.connection_pool.instance_variable_get(:@connections).length}" 35 | results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username]) 36 | user_model.connection_pool.checkin(user_model.connection) 37 | 38 | if results.size > 0 39 | $LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1 40 | user = results.first 41 | if user.crypted_password == user.encrypt(@password) 42 | unless @options[:extra_attributes].blank? 43 | extract_extra(user) 44 | log_extra 45 | end 46 | return true 47 | else 48 | return false 49 | end 50 | else 51 | return false 52 | end 53 | end 54 | 55 | def self.setup(options) 56 | super(options) 57 | user_model.__send__(:include, EncryptedPassword) 58 | end 59 | 60 | module EncryptedPassword 61 | 62 | def self.included(mod) 63 | raise "#{self} should be inclued in an ActiveRecord class!" unless mod.respond_to?(:before_save) 64 | end 65 | 66 | def encrypt(password) 67 | password_digest(password, self.salt) 68 | end 69 | 70 | def secure_digest(*args) 71 | Digest::SHA1.hexdigest(args.flatten.join('--')) 72 | end 73 | 74 | def password_digest(password, salt) 75 | digest = @options[:site_key] 76 | @options[:digest_streches].times do 77 | digest = secure_digest(digest, salt, password, @options[:site_key]) 78 | end 79 | digest 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /lib/casserver/authenticators/test.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require 'casserver/authenticators/base' 3 | 4 | # Dummy authenticator used for testing. 5 | # Accepts any username as valid as long as the password is "testpassword"; otherwise authentication fails. 6 | # Raises an AuthenticationError when username is "do_error" (this is useful to test the Exception 7 | # handling functionality). 8 | class CASServer::Authenticators::Test < CASServer::Authenticators::Base 9 | def validate(credentials) 10 | read_standard_credentials(credentials) 11 | 12 | raise CASServer::AuthenticatorError, "Username is 'do_error'!" if @username == 'do_error' 13 | 14 | @extra_attributes[:test_utf_string] = "Ютф" 15 | @extra_attributes[:test_numeric] = 123.45 16 | @extra_attributes[:test_serialized] = {:foo => 'bar', :alpha => [1,2,3]} 17 | 18 | valid_password = options[:password] || "testpassword" 19 | 20 | return @password == valid_password 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/casserver/cas.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | require 'net/https' 3 | 4 | require 'casserver/model' 5 | 6 | # Encapsulates CAS functionality. This module is meant to be included in 7 | # the CASServer::Controllers module. 8 | module CASServer::CAS 9 | 10 | include CASServer::Model 11 | 12 | def generate_login_ticket 13 | # 3.5 (login ticket) 14 | lt = LoginTicket.new 15 | lt.ticket = "LT-" + CASServer::Utils.random_string 16 | 17 | lt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR'] 18 | lt.save! 19 | $LOG.debug("Generated login ticket '#{lt.ticket}' for client" + 20 | " at '#{lt.client_hostname}'") 21 | lt 22 | end 23 | 24 | # Creates a TicketGrantingTicket for the given username. This is done when the user logs in 25 | # for the first time to establish their SSO session (after their credentials have been validated). 26 | # 27 | # The optional 'extra_attributes' parameter takes a hash of additional attributes 28 | # that will be sent along with the username in the CAS response to subsequent 29 | # validation requests from clients. 30 | def generate_ticket_granting_ticket(username, extra_attributes = {}) 31 | # 3.6 (ticket granting cookie/ticket) 32 | tgt = TicketGrantingTicket.new 33 | tgt.ticket = "TGC-" + CASServer::Utils.random_string 34 | tgt.username = username 35 | tgt.extra_attributes = extra_attributes 36 | tgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR'] 37 | tgt.save! 38 | $LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" + 39 | " '#{tgt.username}' at '#{tgt.client_hostname}'" + 40 | (extra_attributes.blank? ? "" : " with extra attributes #{extra_attributes.inspect}")) 41 | tgt 42 | end 43 | 44 | def generate_service_ticket(service, username, tgt) 45 | # 3.1 (service ticket) 46 | st = ServiceTicket.new 47 | st.ticket = "ST-" + CASServer::Utils.random_string 48 | st.service = service 49 | st.username = username 50 | st.granted_by_tgt_id = tgt.id 51 | st.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR'] 52 | st.save! 53 | $LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" + 54 | " for user '#{st.username}' at '#{st.client_hostname}'") 55 | st 56 | end 57 | 58 | def generate_proxy_ticket(target_service, pgt) 59 | # 3.2 (proxy ticket) 60 | pt = ProxyTicket.new 61 | pt.ticket = "PT-" + CASServer::Utils.random_string 62 | pt.service = target_service 63 | pt.username = pgt.service_ticket.username 64 | pt.granted_by_pgt_id = pgt.id 65 | pt.granted_by_tgt_id = pgt.service_ticket.granted_by_tgt.id 66 | pt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR'] 67 | pt.save! 68 | $LOG.debug("Generated proxy ticket '#{pt.ticket}' for target service '#{pt.service}'" + 69 | " for user '#{pt.username}' at '#{pt.client_hostname}' using proxy-granting" + 70 | " ticket '#{pgt.ticket}'") 71 | pt 72 | end 73 | 74 | def generate_proxy_granting_ticket(pgt_url, st) 75 | uri = URI.parse(pgt_url) 76 | https = Net::HTTP.new(uri.host,uri.port) 77 | https.use_ssl = true 78 | 79 | # Here's what's going on here: 80 | # 81 | # 1. We generate a ProxyGrantingTicket (but don't store it in the database just yet) 82 | # 2. Deposit the PGT and it's associated IOU at the proxy callback URL. 83 | # 3. If the proxy callback URL responds with HTTP code 200, store the PGT and return it; 84 | # otherwise don't save it and return nothing. 85 | # 86 | https.start do |conn| 87 | path = uri.path.empty? ? '/' : uri.path 88 | path += '?' + uri.query unless (uri.query.nil? || uri.query.empty?) 89 | 90 | pgt = ProxyGrantingTicket.new 91 | pgt.ticket = "PGT-" + CASServer::Utils.random_string(60) 92 | pgt.iou = "PGTIOU-" + CASServer::Utils.random_string(57) 93 | pgt.service_ticket_id = st.id 94 | pgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR'] 95 | 96 | # FIXME: The CAS protocol spec says to use 'pgt' as the parameter, but in practice 97 | # the JA-SIG and Yale server implementations use pgtId. We'll go with the 98 | # in-practice standard. 99 | path += (uri.query.nil? || uri.query.empty? ? '?' : '&') + "pgtId=#{pgt.ticket}&pgtIou=#{pgt.iou}" 100 | 101 | response = conn.request_get(path) 102 | # TODO: follow redirects... 2.5.4 says that redirects MAY be followed 103 | # NOTE: The following response codes are valid according to the JA-SIG implementation even without following redirects 104 | 105 | if %w(200 202 301 302 304).include?(response.code) 106 | # 3.4 (proxy-granting ticket IOU) 107 | pgt.save! 108 | $LOG.debug "PGT generated for pgt_url '#{pgt_url}': #{pgt.inspect}" 109 | pgt 110 | else 111 | $LOG.warn "PGT callback server responded with a bad result code '#{response.code}'. PGT will not be stored." 112 | nil 113 | end 114 | end 115 | end 116 | 117 | def validate_login_ticket(ticket) 118 | $LOG.debug("Validating login ticket '#{ticket}'") 119 | 120 | success = false 121 | if ticket.nil? 122 | error = _("Your login request did not include a login ticket. There may be a problem with the authentication system.") 123 | $LOG.warn "Missing login ticket." 124 | elsif lt = LoginTicket.find_by_ticket(ticket) 125 | if lt.consumed? 126 | error = _("The login ticket you provided has already been used up. Please try logging in again.") 127 | $LOG.warn "Login ticket '#{ticket}' previously used up" 128 | elsif Time.now - lt.created_on < settings.config[:maximum_unused_login_ticket_lifetime] 129 | $LOG.info "Login ticket '#{ticket}' successfully validated" 130 | else 131 | error = _("You took too long to enter your credentials. Please try again.") 132 | $LOG.warn "Expired login ticket '#{ticket}'" 133 | end 134 | else 135 | error = _("The login ticket you provided is invalid. There may be a problem with the authentication system.") 136 | $LOG.warn "Invalid login ticket '#{ticket}'" 137 | end 138 | 139 | lt.consume! if lt 140 | 141 | error 142 | end 143 | 144 | def validate_ticket_granting_ticket(ticket) 145 | $LOG.debug("Validating ticket granting ticket '#{ticket}'") 146 | 147 | if ticket.nil? 148 | error = "No ticket granting ticket given." 149 | $LOG.debug error 150 | elsif tgt = TicketGrantingTicket.find_by_ticket(ticket) 151 | if settings.config[:maximum_session_lifetime] && Time.now - tgt.created_on > settings.config[:maximum_session_lifetime] 152 | tgt.destroy 153 | error = "Your session has expired. Please log in again." 154 | $LOG.info "Ticket granting ticket '#{ticket}' for user '#{tgt.username}' expired." 155 | else 156 | $LOG.info "Ticket granting ticket '#{ticket}' for user '#{tgt.username}' successfully validated." 157 | end 158 | else 159 | error = "Invalid ticket granting ticket '#{ticket}' (no matching ticket found in the database)." 160 | $LOG.warn(error) 161 | end 162 | 163 | [tgt, error] 164 | end 165 | 166 | def validate_service_ticket(service, ticket, allow_proxy_tickets = false) 167 | $LOG.debug "Validating service/proxy ticket '#{ticket}' for service '#{service}'" 168 | 169 | if service.nil? or ticket.nil? 170 | error = Error.new(:INVALID_REQUEST, "Ticket or service parameter was missing in the request.") 171 | $LOG.warn "#{error.code} - #{error.message}" 172 | elsif st = ServiceTicket.find_by_ticket(ticket) 173 | if st.consumed? 174 | error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' has already been used up.") 175 | $LOG.warn "#{error.code} - #{error.message}" 176 | elsif st.kind_of?(CASServer::Model::ProxyTicket) && !allow_proxy_tickets 177 | error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' is a proxy ticket, but only service tickets are allowed here.") 178 | $LOG.warn "#{error.code} - #{error.message}" 179 | elsif Time.now - st.created_on > settings.config[:maximum_unused_service_ticket_lifetime] 180 | error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' has expired.") 181 | $LOG.warn "Ticket '#{ticket}' has expired." 182 | elsif !st.matches_service? service 183 | error = Error.new(:INVALID_SERVICE, "The ticket '#{ticket}' belonging to user '#{st.username}' is valid,"+ 184 | " but the requested service '#{service}' does not match the service '#{st.service}' associated with this ticket.") 185 | $LOG.warn "#{error.code} - #{error.message}" 186 | else 187 | $LOG.info("Ticket '#{ticket}' for service '#{service}' for user '#{st.username}' successfully validated.") 188 | end 189 | else 190 | error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' not recognized.") 191 | $LOG.warn("#{error.code} - #{error.message}") 192 | end 193 | 194 | if st 195 | st.consume! 196 | end 197 | 198 | 199 | [st, error] 200 | end 201 | 202 | def validate_proxy_ticket(service, ticket) 203 | pt, error = validate_service_ticket(service, ticket, true) 204 | 205 | if pt.kind_of?(CASServer::Model::ProxyTicket) && !error 206 | if not pt.granted_by_pgt 207 | error = Error.new(:INTERNAL_ERROR, "Proxy ticket '#{pt}' belonging to user '#{pt.username}' is not associated with a proxy granting ticket.") 208 | elsif not pt.granted_by_pgt.service_ticket 209 | error = Error.new(:INTERNAL_ERROR, "Proxy granting ticket '#{pt.granted_by_pgt}'"+ 210 | " (associated with proxy ticket '#{pt}' and belonging to user '#{pt.username}' is not associated with a service ticket.") 211 | end 212 | end 213 | 214 | [pt, error] 215 | end 216 | 217 | def validate_proxy_granting_ticket(ticket) 218 | if ticket.nil? 219 | error = Error.new(:INVALID_REQUEST, "pgt parameter was missing in the request.") 220 | $LOG.warn("#{error.code} - #{error.message}") 221 | elsif pgt = ProxyGrantingTicket.find_by_ticket(ticket) 222 | if pgt.service_ticket 223 | $LOG.info("Proxy granting ticket '#{ticket}' belonging to user '#{pgt.service_ticket.username}' successfully validated.") 224 | else 225 | error = Error.new(:INTERNAL_ERROR, "Proxy granting ticket '#{ticket}' is not associated with a service ticket.") 226 | $LOG.error("#{error.code} - #{error.message}") 227 | end 228 | else 229 | error = Error.new(:BAD_PGT, "Invalid proxy granting ticket '#{ticket}' (no matching ticket found in the database).") 230 | $LOG.warn("#{error.code} - #{error.message}") 231 | end 232 | 233 | [pgt, error] 234 | end 235 | 236 | # Takes an existing ServiceTicket object (presumably pulled from the database) 237 | # and sends a POST with logout information to the service that the ticket 238 | # was generated for. 239 | # 240 | # This makes possible the "single sign-out" functionality added in CAS 3.1. 241 | # See http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out 242 | def send_logout_notification_for_service_ticket(st) 243 | uri = URI.parse(st.service) 244 | uri.path = '/' if uri.path.empty? 245 | time = Time.now 246 | rand = CASServer::Utils.random_string 247 | 248 | begin 249 | response = Net::HTTP.post_form(uri, {'logoutRequest' => URI.escape(%{ 250 | 251 | #{st.ticket} 252 | })}) 253 | if response.kind_of? Net::HTTPSuccess 254 | $LOG.info "Logout notification successfully posted to #{st.service.inspect}." 255 | return true 256 | else 257 | $LOG.error "Service #{st.service.inspect} responed to logout notification with code '#{response.code}'!" 258 | return false 259 | end 260 | rescue Exception => e 261 | $LOG.error "Failed to send logout notification to service #{st.service.inspect} due to #{e}" 262 | return false 263 | end 264 | end 265 | 266 | def service_uri_with_ticket(service, st) 267 | raise ArgumentError, "Second argument must be a ServiceTicket!" unless st.kind_of? CASServer::Model::ServiceTicket 268 | 269 | # This will choke with a URI::InvalidURIError if service URI is not properly URI-escaped... 270 | # This exception is handled further upstream (i.e. in the controller). 271 | service_uri = URI.parse(service) 272 | 273 | if service.include? "?" 274 | if service_uri.query.empty? 275 | query_separator = "" 276 | else 277 | query_separator = "&" 278 | end 279 | else 280 | query_separator = "?" 281 | end 282 | 283 | service_with_ticket = service + query_separator + "ticket=" + st.ticket 284 | service_with_ticket 285 | end 286 | 287 | # Strips CAS-related parameters from a service URL and normalizes it, 288 | # removing trailing / and ?. Also converts any spaces to +. 289 | # 290 | # For example, "http://google.com?ticket=12345" will be returned as 291 | # "http://google.com". Also, "http://google.com/" would be returned as 292 | # "http://google.com". 293 | # 294 | # Note that only the first occurance of each CAS-related parameter is 295 | # removed, so that "http://google.com?ticket=12345&ticket=abcd" would be 296 | # returned as "http://google.com?ticket=abcd". 297 | def clean_service_url(dirty_service) 298 | return dirty_service if dirty_service.blank? 299 | clean_service = dirty_service.dup 300 | ['service', 'ticket', 'gateway', 'renew'].each do |p| 301 | clean_service.sub!(Regexp.new("&?#{p}=[^&]*"), '') 302 | end 303 | 304 | clean_service.gsub!(/[\/\?&]$/, '') # remove trailing ?, /, or & 305 | clean_service.gsub!('?&', '?') 306 | clean_service.gsub!(' ', '+') 307 | 308 | $LOG.debug("Cleaned dirty service URL #{dirty_service.inspect} to #{clean_service.inspect}") if 309 | dirty_service != clean_service 310 | 311 | return clean_service 312 | end 313 | module_function :clean_service_url 314 | 315 | end 316 | -------------------------------------------------------------------------------- /lib/casserver/localization.rb: -------------------------------------------------------------------------------- 1 | require "gettext" 2 | require "gettext/cgi" 3 | require 'active_support' 4 | 5 | module CASServer 6 | module Localization 7 | def self.included(mod) 8 | mod.module_eval do 9 | include GetText 10 | end 11 | end 12 | 13 | include GetText 14 | bindtextdomain("rubycas-server", :path => File.join(File.dirname(File.expand_path(__FILE__)), "../../locale")) 15 | 16 | def determine_locale(request) 17 | source = nil 18 | lang = case 19 | when !request.params['lang'].blank? 20 | source = "'lang' request variable" 21 | request.cookies['lang'] = request.params['lang'] 22 | request.params['lang'] 23 | when !request.cookies['lang'].blank? 24 | source = "'lang' cookie" 25 | request.cookies['lang'] 26 | when !request.env['HTTP_ACCEPT_LANGUAGE'].blank? 27 | source = "'HTTP_ACCEPT_LANGUAGE' header" 28 | lang = request.env['HTTP_ACCEPT_LANGUAGE'] 29 | when !request.env['HTTP_USER_AGENT'].blank? && request.env['HTTP_USER_AGENT'] =~ /[^a-z]([a-z]{2}(-[a-z]{2})?)[^a-z]/i 30 | source = "'HTTP_USER_AGENT' header" 31 | $~[1] 32 | # when !$CONF['default_locale'].blank? 33 | # source = "'default_locale' config option" 34 | # $CONF[:default_locale] 35 | else 36 | source = "default" 37 | "en" 38 | end 39 | 40 | $LOG.debug "Detected locale is #{lang.inspect} (from #{source})" 41 | 42 | lang.gsub!('_','-') 43 | 44 | # TODO: Need to confirm that this method of splitting the accepted 45 | # language string is correct. 46 | if lang =~ /[,;\|]/ 47 | langs = lang.split(/[,;\|]/) 48 | else 49 | langs = [lang] 50 | end 51 | 52 | # TODO: This method of selecting the desired language might not be 53 | # standards-compliant. For example, http://www.w3.org/TR/ltli/ 54 | # suggests that de-de and de-*-DE might be acceptable identifiers 55 | # for selecting various wildcards. The algorithm below does not 56 | # currently support anything like this. 57 | 58 | available = available_locales 59 | 60 | if available.length == 1 61 | $LOG.warn "Only the #{available.first.inspect} localization is available. You should run `rake localization:mo` to compile support for additional languages!" 62 | elsif available.length == 0 # this should never actually happen 63 | $LOG.error "No localizations available! Run `rake localization:mo` to compile support for additional languages." 64 | end 65 | 66 | # Try to pick a locale exactly matching the desired identifier, otherwise 67 | # fall back to locale without region (i.e. given "en-US; de-DE", we would 68 | # first look for "en-US", then "en", then "de-DE", then "de"). 69 | 70 | chosen_lang = nil 71 | langs.each do |l| 72 | a = available.find{ |a| a =~ Regexp.new("\\A#{l}\\Z", 'i') || 73 | a =~ Regexp.new("#{l}-\w*", 'i') } 74 | if a 75 | chosen_lang = a 76 | break 77 | end 78 | end 79 | 80 | chosen_lang = "en" if chosen_lang.blank? 81 | 82 | $LOG.debug "Chosen locale is #{chosen_lang.inspect}" 83 | 84 | return chosen_lang 85 | end 86 | 87 | def available_locales 88 | (Dir.glob(File.join(File.dirname(File.expand_path(__FILE__)), "../../locale/[a-z]*")).map{|path| File.basename(path)} << "en").uniq.collect{|l| l.gsub('_','-')} 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/casserver/model.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | require 'active_record/base' 3 | 4 | module CASServer::Model 5 | 6 | module Consumable 7 | def consume! 8 | self.consumed = Time.now 9 | self.save! 10 | end 11 | 12 | def self.included(mod) 13 | mod.extend(ClassMethods) 14 | end 15 | 16 | module ClassMethods 17 | def cleanup(max_lifetime, max_unconsumed_lifetime) 18 | transaction do 19 | conditions = ["created_on < ? OR (consumed IS NULL AND created_on < ?)", 20 | Time.now - max_lifetime, 21 | Time.now - max_unconsumed_lifetime] 22 | 23 | expired_tickets_count = count(:conditions => conditions) 24 | 25 | $LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.demodulize}"+ 26 | "#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0 27 | 28 | destroy_all(conditions) 29 | end 30 | end 31 | end 32 | end 33 | 34 | class Base < ActiveRecord::Base 35 | end 36 | 37 | class Ticket < Base 38 | def to_s 39 | ticket 40 | end 41 | 42 | def self.cleanup(max_lifetime) 43 | transaction do 44 | conditions = ["created_on < ?", Time.now - max_lifetime] 45 | expired_tickets_count = count(:conditions => conditions) 46 | 47 | $LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.demodulize}"+ 48 | "#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0 49 | 50 | destroy_all(conditions) 51 | end 52 | end 53 | end 54 | 55 | class LoginTicket < Ticket 56 | set_table_name 'casserver_lt' 57 | include Consumable 58 | end 59 | 60 | class ServiceTicket < Ticket 61 | set_table_name 'casserver_st' 62 | include Consumable 63 | 64 | belongs_to :granted_by_tgt, 65 | :class_name => 'CASServer::Model::TicketGrantingTicket', 66 | :foreign_key => :granted_by_tgt_id 67 | has_one :proxy_granting_ticket, 68 | :foreign_key => :created_by_st_id 69 | 70 | def matches_service?(service) 71 | CASServer::CAS.clean_service_url(self.service) == 72 | CASServer::CAS.clean_service_url(service) 73 | end 74 | end 75 | 76 | class ProxyTicket < ServiceTicket 77 | belongs_to :granted_by_pgt, 78 | :class_name => 'CASServer::Model::ProxyGrantingTicket', 79 | :foreign_key => :granted_by_pgt_id 80 | end 81 | 82 | class TicketGrantingTicket < Ticket 83 | set_table_name 'casserver_tgt' 84 | 85 | serialize :extra_attributes 86 | 87 | has_many :granted_service_tickets, 88 | :class_name => 'CASServer::Model::ServiceTicket', 89 | :foreign_key => :granted_by_tgt_id 90 | end 91 | 92 | class ProxyGrantingTicket < Ticket 93 | set_table_name 'casserver_pgt' 94 | belongs_to :service_ticket 95 | has_many :granted_proxy_tickets, 96 | :class_name => 'CASServer::Model::ProxyTicket', 97 | :foreign_key => :granted_by_pgt_id 98 | end 99 | 100 | class Error 101 | attr_reader :code, :message 102 | 103 | def initialize(code, message) 104 | @code = code 105 | @message = message 106 | end 107 | 108 | def to_s 109 | message 110 | end 111 | end 112 | 113 | # class CreateCASServer < V 0.1 114 | # def self.up 115 | # if ActiveRecord::Base.connection.table_alias_length > 30 116 | # $LOG.info("Creating database with long table names...") 117 | # 118 | # create_table :casserver_login_tickets, :force => true do |t| 119 | # t.column :ticket, :string, :null => false 120 | # t.column :created_on, :timestamp, :null => false 121 | # t.column :consumed, :datetime, :null => true 122 | # t.column :client_hostname, :string, :null => false 123 | # end 124 | # 125 | # create_table :casserver_service_tickets, :force => true do |t| 126 | # t.column :ticket, :string, :null => false 127 | # t.column :service, :string, :null => false 128 | # t.column :created_on, :timestamp, :null => false 129 | # t.column :consumed, :datetime, :null => true 130 | # t.column :client_hostname, :string, :null => false 131 | # t.column :username, :string, :null => false 132 | # t.column :type, :string, :null => false 133 | # t.column :proxy_granting_ticket_id, :integer, :null => true 134 | # end 135 | # 136 | # create_table :casserver_ticket_granting_tickets, :force => true do |t| 137 | # t.column :ticket, :string, :null => false 138 | # t.column :created_on, :timestamp, :null => false 139 | # t.column :client_hostname, :string, :null => false 140 | # t.column :username, :string, :null => false 141 | # end 142 | # 143 | # create_table :casserver_proxy_granting_tickets, :force => true do |t| 144 | # t.column :ticket, :string, :null => false 145 | # t.column :created_on, :timestamp, :null => false 146 | # t.column :client_hostname, :string, :null => false 147 | # t.column :iou, :string, :null => false 148 | # t.column :service_ticket_id, :integer, :null => false 149 | # end 150 | # end 151 | # end 152 | # 153 | # def self.down 154 | # if ActiveRecord::Base.connection.table_alias_length > 30 155 | # drop_table :casserver_proxy_granting_tickets 156 | # drop_table :casserver_ticket_granting_tickets 157 | # drop_table :casserver_service_tickets 158 | # drop_table :casserver_login_tickets 159 | # end 160 | # end 161 | # end 162 | # 163 | # # Oracle table names cannot exceed 30 chars... 164 | # # See http://code.google.com/p/rubycas-server/issues/detail?id=15 165 | # class ShortenTableNames < V 0.5 166 | # def self.up 167 | # if ActiveRecord::Base.connection.table_alias_length > 30 168 | # $LOG.info("Shortening table names") 169 | # rename_table :casserver_login_tickets, :casserver_lt 170 | # rename_table :casserver_service_tickets, :casserver_st 171 | # rename_table :casserver_ticket_granting_tickets, :casserver_tgt 172 | # rename_table :casserver_proxy_granting_tickets, :casserver_pgt 173 | # else 174 | # create_table :casserver_lt, :force => true do |t| 175 | # t.column :ticket, :string, :null => false 176 | # t.column :created_on, :timestamp, :null => false 177 | # t.column :consumed, :datetime, :null => true 178 | # t.column :client_hostname, :string, :null => false 179 | # end 180 | # 181 | # create_table :casserver_st, :force => true do |t| 182 | # t.column :ticket, :string, :null => false 183 | # t.column :service, :string, :null => false 184 | # t.column :created_on, :timestamp, :null => false 185 | # t.column :consumed, :datetime, :null => true 186 | # t.column :client_hostname, :string, :null => false 187 | # t.column :username, :string, :null => false 188 | # t.column :type, :string, :null => false 189 | # t.column :proxy_granting_ticket_id, :integer, :null => true 190 | # end 191 | # 192 | # create_table :casserver_tgt, :force => true do |t| 193 | # t.column :ticket, :string, :null => false 194 | # t.column :created_on, :timestamp, :null => false 195 | # t.column :client_hostname, :string, :null => false 196 | # t.column :username, :string, :null => false 197 | # end 198 | # 199 | # create_table :casserver_pgt, :force => true do |t| 200 | # t.column :ticket, :string, :null => false 201 | # t.column :created_on, :timestamp, :null => false 202 | # t.column :client_hostname, :string, :null => false 203 | # t.column :iou, :string, :null => false 204 | # t.column :service_ticket_id, :integer, :null => false 205 | # end 206 | # end 207 | # end 208 | # 209 | # def self.down 210 | # if ActiveRecord::Base.connection.table_alias_length > 30 211 | # rename_table :casserver_lt, :cassserver_login_tickets 212 | # rename_table :casserver_st, :casserver_service_tickets 213 | # rename_table :casserver_tgt, :casserver_ticket_granting_tickets 214 | # rename_table :casserver_pgt, :casserver_proxy_granting_tickets 215 | # else 216 | # drop_table :casserver_pgt 217 | # drop_table :casserver_tgt 218 | # drop_table :casserver_st 219 | # drop_table :casserver_lt 220 | # end 221 | # end 222 | # end 223 | # 224 | # class AddTgtToSt < V 0.7 225 | # def self.up 226 | # add_column :casserver_st, :tgt_id, :integer, :null => true 227 | # end 228 | # 229 | # def self.down 230 | # remove_column :casserver_st, :tgt_id, :integer 231 | # end 232 | # end 233 | # 234 | # class ChangeServiceToText < V 0.71 235 | # def self.up 236 | # # using change_column to change the column type from :string to :text 237 | # # doesn't seem to work, at least under MySQL, so we drop and re-create 238 | # # the column instead 239 | # remove_column :casserver_st, :service 240 | # say "WARNING: All existing service tickets are being deleted." 241 | # add_column :casserver_st, :service, :text 242 | # end 243 | # 244 | # def self.down 245 | # change_column :casserver_st, :service, :string 246 | # end 247 | # end 248 | # 249 | # class AddExtraAttributes < V 0.72 250 | # def self.up 251 | # add_column :casserver_tgt, :extra_attributes, :text 252 | # end 253 | # 254 | # def self.down 255 | # remove_column :casserver_tgt, :extra_attributes 256 | # end 257 | # end 258 | # 259 | # class RenamePgtForeignKeys < V 0.80 260 | # def self.up 261 | # rename_column :casserver_st, :proxy_granting_ticket_id, :granted_by_pgt_id 262 | # rename_column :casserver_st, :tgt_id, :granted_by_tgt_id 263 | # end 264 | # 265 | # def self.down 266 | # rename_column :casserver_st, :granted_by_pgt_id, :proxy_granting_ticket_id 267 | # rename_column :casserver_st, :granted_by_tgt_id, :tgt_id 268 | # end 269 | # end 270 | end 271 | -------------------------------------------------------------------------------- /lib/casserver/utils.rb: -------------------------------------------------------------------------------- 1 | require 'crypt-isaac' 2 | 3 | # Misc utility function used throughout by the RubyCAS-Server. 4 | module CASServer 5 | module Utils 6 | def random_string(max_length = 29) 7 | rg = Crypt::ISAAC.new 8 | max = 4294619050 9 | r = "#{Time.now.to_i}r%X%X%X%X%X%X%X%X" % 10 | [rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max), 11 | rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max)] 12 | r[0..max_length-1] 13 | end 14 | module_function :random_string 15 | 16 | def log_controller_action(controller, params) 17 | $LOG << "\n" 18 | 19 | /`(.*)'/.match(caller[1]) 20 | method = $~[1] 21 | 22 | if params.respond_to? :dup 23 | params2 = params.dup 24 | params2['password'] = '******' if params2['password'] 25 | else 26 | params2 = params 27 | end 28 | $LOG.debug("Processing #{controller}::#{method} #{params2.inspect}") 29 | end 30 | module_function :log_controller_action 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/casserver/views/_login_form.erb: -------------------------------------------------------------------------------- 1 | <%# coding: UTF-8 -%> 2 |
" id="login-form" 3 | onsubmit="submitbutton = document.getElementById('login-submit'); submitbutton.value='<%= _("Please wait...") %>'; submitbutton.disabled=true; return true;"> 4 | 5 | 6 | 11 | 15 | 16 | 17 | 22 | 26 | 27 | 28 | 35 | 36 | 37 | 40 | 41 |
7 | 10 | 12 | 14 |
18 | 21 | 23 | 25 |
29 | 30 | 31 | 32 | " 33 | tabindex="4" id="login-submit" /> 34 |
38 | <%= @infoline %> 39 |
42 |
43 | -------------------------------------------------------------------------------- /lib/casserver/views/layout.erb: -------------------------------------------------------------------------------- 1 | <%# coding: UTF-8 -%> 2 | 3 | 5 | 7 | 8 | 9 | <%= escape_html @organization %><%= _(" Central Login") %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | <%= yield %> 17 | 18 | 19 | -------------------------------------------------------------------------------- /lib/casserver/views/login.erb: -------------------------------------------------------------------------------- 1 | <%# coding: UTF-8 -%> 2 | 3 | 4 | 10 | 11 | 12 | <% if @message %> 13 | 14 | 19 | 20 | <% end %> 21 | 22 | 23 | 26 | 29 | 30 |
5 |
6 | <%= escape_html @organization %> 7 | <%= _(" Central Login") %> 8 |
9 |
15 |
16 | <%= escape_html @message[:message] %> 17 |
18 |
24 | 25 | 27 | <%= erb(:_login_form, :layout => false) %> 28 |
31 | -------------------------------------------------------------------------------- /lib/casserver/views/proxy.builder: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | if @success 3 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 4 | xml.tag!("cas:proxySuccess") do 5 | xml.tag!("cas:proxyTicket", @pt.to_s) 6 | end 7 | end 8 | else 9 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 10 | xml.tag!("cas:proxyFailure", {:code => @error.code}, @error.to_s) 11 | end 12 | end -------------------------------------------------------------------------------- /lib/casserver/views/proxy_validate.builder: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | if @success 3 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 4 | xml.tag!("cas:authenticationSuccess") do 5 | xml.tag!("cas:user", @username.to_s) 6 | @extra_attributes.each do |key, value| 7 | serialize_extra_attribute(xml, key, value) 8 | end 9 | if @pgtiou 10 | xml.tag!("cas:proxyGrantingTicket", @pgtiou.to_s) 11 | end 12 | if @proxies && !@proxies.empty? 13 | xml.tag!("cas:proxies") do 14 | @proxies.each do |proxy_url| 15 | xml.tag!("cas:proxy", proxy_url.to_s) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | else 22 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 23 | xml.tag!("cas:authenticationFailure", {:code => @error.code}, @error.to_s) 24 | end 25 | end -------------------------------------------------------------------------------- /lib/casserver/views/service_validate.builder: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | if @success 3 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 4 | xml.tag!("cas:authenticationSuccess") do 5 | xml.tag!("cas:user", @username.to_s) 6 | @extra_attributes.each do |key, value| 7 | serialize_extra_attribute(xml, key, value) 8 | end 9 | if @pgtiou 10 | xml.tag!("cas:proxyGrantingTicket", @pgtiou.to_s) 11 | end 12 | end 13 | end 14 | else 15 | xml.tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do 16 | xml.tag!("cas:authenticationFailure", {:code => @error.code}, @error.to_s) 17 | end 18 | end -------------------------------------------------------------------------------- /lib/casserver/views/validate.erb: -------------------------------------------------------------------------------- 1 | <%# coding: UTF-8 %> 2 | <%= @success ? "yes\n#{@username}\n" : "no\n\n" %> 3 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/log/.gitignore -------------------------------------------------------------------------------- /po/de_DE/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # German translations for RubyCAS-Server package 2 | # German messages for RubyCAS-Server. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Matt Zukowski , 2008. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-11-12 12:49-0500\n" 12 | "Last-Translator: Matt Zukowski \n" 13 | "Language-Team: German\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "" 45 | "Sie sind derzeit angemeldet als '%s'. Sollten dies nicht Sie sein, melden " 46 | "Sie sich bitte unten an." 47 | 48 | #: lib/casserver/controllers.rb:37 49 | msgid "" 50 | "The client and server are unable to negotiate authentication. Please try " 51 | "logging in again later." 52 | msgstr "" 53 | "Client und Server sind nicht in der Lage eine Authentifizierung " 54 | "auszuhandeln. Bitte versuchen Sie, sich zu einem späteren Zeitpunkt erneut " 55 | "anzumelden." 56 | 57 | #: lib/casserver/controllers.rb:54 58 | msgid "" 59 | "The server cannot fulfill this gateway request because no service parameter " 60 | "was given." 61 | msgstr "" 62 | "Der Server kann diese Gateway-Anfrage nicht erfüllen, da keine Service-" 63 | "Parameter übergeben wurden." 64 | 65 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 66 | msgid "" 67 | "The target service your browser supplied appears to be invalid. Please " 68 | "contact your system administrator for help." 69 | msgstr "" 70 | "Das Ziel-Service, welches Ihr Browsers geliefert hat, scheint ungültig zu " 71 | "sein. Bitte wenden Sie sich an Ihren Systemadministrator, um Hilfe zu " 72 | "erhalten." 73 | 74 | #: lib/casserver/controllers.rb:88 75 | msgid "" 76 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 77 | "with your request." 78 | msgstr "" 79 | "Der CAS-Login-URI konnte nicht erraten werden. Bitte ergänzen Sie Ihre " 80 | "Anfrage um einen submitToURI Parameter." 81 | 82 | #: lib/casserver/controllers.rb:168 83 | msgid "You have successfully logged in." 84 | msgstr "" 85 | "Sie haben sich erfolgreich am Central Authentication Service angemeldet." 86 | 87 | #: lib/casserver/controllers.rb:184 88 | msgid "Incorrect username or password." 89 | msgstr "Falscher Benutzername oder Passwort." 90 | 91 | #: lib/casserver/controllers.rb:267 92 | msgid "You have successfully logged out." 93 | msgstr "" 94 | "Sie haben sich erfolgreich vom Central Authentication Service abgemeldet." 95 | 96 | #: lib/casserver/controllers.rb:269 97 | msgid " Please click on the following link to continue:" 98 | msgstr " Bitte klicken Sie auf den folgenden Link, um fortzufahren:" 99 | 100 | #: lib/casserver/controllers.rb:419 101 | msgid "To generate a login ticket, you must make a POST request." 102 | msgstr "" 103 | "Für die Generierung eines Login-Tickets, ist eine POST-Anfrage erforderlich." 104 | 105 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 106 | msgid " Central Login" 107 | msgstr " Zentrales Login" 108 | 109 | #: lib/casserver/views.rb:68 110 | msgid "Please wait..." 111 | msgstr "" 112 | 113 | #: lib/casserver/views.rb:74 114 | msgid "Username" 115 | msgstr "Benutzername" 116 | 117 | #: lib/casserver/views.rb:83 118 | msgid "Password" 119 | msgstr "Passwort" 120 | 121 | #: lib/casserver/views.rb:92 122 | msgid "Remeber me on this computer" 123 | msgstr "" 124 | 125 | #: lib/casserver/views.rb:101 126 | msgid "LOGIN" 127 | msgstr "ANMELDEN" 128 | -------------------------------------------------------------------------------- /po/es_ES/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Spanish translations for RubyCAS-Server package 2 | # Traducciones al espa ol para el paquete RubyCAS-Server. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Matt Zukowski , 2008. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-11-12 12:30-0500\n" 12 | "Last-Translator: Matt Zukowski \n" 13 | "Language-Team: Spanish\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "" 45 | "Usted está conectado como '%s'. Si no lo es usted, por favor, acceda a " 46 | "continuación." 47 | 48 | #: lib/casserver/controllers.rb:37 49 | msgid "" 50 | "The client and server are unable to negotiate authentication. Please try " 51 | "logging in again later." 52 | msgstr "" 53 | "El cliente y el servidor no están en condiciones de negociar la " 54 | "autenticación. Por favor, intente acceder de nuevo más tarde." 55 | 56 | #: lib/casserver/controllers.rb:54 57 | msgid "" 58 | "The server cannot fulfill this gateway request because no service parameter " 59 | "was given." 60 | msgstr "" 61 | "El servidor no puede cumplir con esta petición, porque no fue parámetro de " 62 | "servicio prestado." 63 | 64 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 65 | msgid "" 66 | "The target service your browser supplied appears to be invalid. Please " 67 | "contact your system administrator for help." 68 | msgstr "" 69 | "El objetivo de su navegador de servicios ofrecidos parece ser nula. Por " 70 | "favor, póngase en contacto con el administrador del sistema para obtener " 71 | "ayuda." 72 | 73 | #: lib/casserver/controllers.rb:88 74 | msgid "" 75 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 76 | "with your request." 77 | msgstr "" 78 | "No podía adivinar el URI de acceso CAS. Suministro submitToURI un parámetro " 79 | "con su solicitud." 80 | 81 | #: lib/casserver/controllers.rb:168 82 | msgid "You have successfully logged in." 83 | msgstr "Inicio de sesión satisfactorio." 84 | 85 | #: lib/casserver/controllers.rb:184 86 | msgid "Incorrect username or password." 87 | msgstr "Incorrecto nombre de usuario o contraseña." 88 | 89 | #: lib/casserver/controllers.rb:267 90 | msgid "You have successfully logged out." 91 | msgstr "Cierre de sesión satisfactorio." 92 | 93 | #: lib/casserver/controllers.rb:269 94 | msgid " Please click on the following link to continue:" 95 | msgstr " Por favor, haga clic en el vínculo siguiente para continuar:" 96 | 97 | #: lib/casserver/controllers.rb:419 98 | msgid "To generate a login ticket, you must make a POST request." 99 | msgstr "Para generar un ticket de acceso, usted debe hacer una petición POST." 100 | 101 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 102 | msgid " Central Login" 103 | msgstr " Servicio de Autenticación Central" 104 | 105 | #: lib/casserver/views.rb:68 106 | msgid "Please wait..." 107 | msgstr "" 108 | 109 | #: lib/casserver/views.rb:74 110 | msgid "Username" 111 | msgstr "Usuario" 112 | 113 | #: lib/casserver/views.rb:83 114 | msgid "Password" 115 | msgstr "Contraseña" 116 | 117 | #: lib/casserver/views.rb:92 118 | msgid "Remeber me on this computer" 119 | msgstr "" 120 | 121 | #: lib/casserver/views.rb:101 122 | msgid "LOGIN" 123 | msgstr "INICIAR SESIÓN" 124 | -------------------------------------------------------------------------------- /po/fr_FR/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # French translations for RubyCAS-Server package 2 | # Traductions françaises du paquet RubyCAS-Server. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Matt Zukowski , 2008. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-11-12 11:53-0500\n" 12 | "Last-Translator: Matt Zukowski \n" 13 | "Language-Team: French\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | "Votre requête d'identification n'a pas inclus de ticket d'identification. Il se peut qu'il y ait un problème " 25 | "avec le système d'identification." 26 | 27 | #: lib/casserver/cas.rb:121 28 | msgid "" 29 | "The login ticket you provided has already been used up. Please try logging " 30 | "in again." 31 | msgstr "" 32 | "Le ticket d'identification que vous avez fourni a été consommé. Veuillez essayer " 33 | " de vous reconnecter" 34 | 35 | #: lib/casserver/cas.rb:126 36 | msgid "You took too long to enter your credentials. Please try again." 37 | msgstr "Le délai de saisie de vos login et mot de passe a expiré. Veuillez réessayer." 38 | 39 | #: lib/casserver/cas.rb:130 40 | msgid "" 41 | "The login ticket you provided is invalid. There may be a problem with the " 42 | "authentication system." 43 | msgstr "" 44 | "Le ticket d'identification que vous avez fourni n'est pas valide. Il se peut qu'il y ait " 45 | "un problème avec le système d'identification." 46 | 47 | #: lib/casserver/controllers.rb:32 48 | msgid "" 49 | "You are currently logged in as '%s'. If this is not you, please log in below." 50 | msgstr "" 51 | "Vous êtes actuellement connecté en tant que '%s'. Si ce n'est pas vous, " 52 | "veuillez vous connecter ci-dessous." 53 | 54 | #: lib/casserver/controllers.rb:37 55 | msgid "" 56 | "The client and server are unable to negotiate authentication. Please try " 57 | "logging in again later." 58 | msgstr "" 59 | "Le client et le serveur ne peuvent négocier l'identification. " 60 | "Veuillez réessayer ultérieurement." 61 | 62 | #: lib/casserver/controllers.rb:54 63 | msgid "" 64 | "The server cannot fulfill this gateway request because no service parameter " 65 | "was given." 66 | msgstr "" 67 | "Le serveur ne peut pas répondre à cette demande (aucun paramètre de service " 68 | "n'a été donné)." 69 | 70 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 71 | msgid "" 72 | "The target service your browser supplied appears to be invalid. Please " 73 | "contact your system administrator for help." 74 | msgstr "" 75 | "Le service cible que votre navigateur a fourni semble incorrect. " 76 | "Veuillez contacter votre administrateur système pour assistance." 77 | 78 | #: lib/casserver/controllers.rb:88 79 | msgid "" 80 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 81 | "with your request." 82 | msgstr "" 83 | "Impossible de trouver l'URI de connection de CAS. Veuillez fournir le paramètre " 84 | "submitToURI avec votre requête." 85 | 86 | #: lib/casserver/controllers.rb:168 87 | msgid "You have successfully logged in." 88 | msgstr "Vous vous êtes authentifié(e) auprès du Service Central d'Identification." 89 | 90 | #: lib/casserver/controllers.rb:184 91 | msgid "Incorrect username or password." 92 | msgstr "Les informations transmises n'ont pas permis de vous authentifier" 93 | 94 | #: lib/casserver/controllers.rb:267 95 | msgid "You have successfully logged out." 96 | msgstr "Vous vous êtes déconnecté(e) du Service Central d'Identification." 97 | 98 | #: lib/casserver/controllers.rb:269 99 | msgid " Please click on the following link to continue:" 100 | msgstr " S'il vous plaît cliquer sur le lien suivant pour continuer:" 101 | 102 | #: lib/casserver/controllers.rb:419 103 | msgid "To generate a login ticket, you must make a POST request." 104 | msgstr "Pour générer un ticket de connexion, vous devez faire une requête POST." 105 | 106 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 107 | msgid " Central Login" 108 | msgstr " Service Central d'Identification." 109 | 110 | #: lib/casserver/views.rb:68 111 | msgid "Please wait..." 112 | msgstr "Veuillez patienter..." 113 | 114 | #: lib/casserver/views.rb:74 115 | msgid "Username" 116 | msgstr "Identifiant" 117 | 118 | #: lib/casserver/views.rb:83 119 | msgid "Password" 120 | msgstr "Mot de passe" 121 | 122 | #: lib/casserver/views.rb:92 123 | msgid "Remeber me on this computer" 124 | msgstr "Se souvenir de moi" 125 | 126 | #: lib/casserver/views.rb:101 127 | msgid "LOGIN" 128 | msgstr "SE CONNECTER" 129 | -------------------------------------------------------------------------------- /po/ja_JP/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Japanese translations for RubyCAS-Server package 2 | # RubyCAS-Server パッケージに対する英訳. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Matt Zukowski , 2008. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-11-12 13:04-0500\n" 12 | "Last-Translator: Matt Zukowski \n" 13 | "Language-Team: Japanese\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | "ログインリクエストにログインチケットが含まれていません。認証システムに問題があるようです。" 25 | 26 | #: lib/casserver/cas.rb:121 27 | msgid "" 28 | "The login ticket you provided has already been used up. Please try logging " 29 | "in again." 30 | msgstr "" 31 | "ログインチケットはすでに使い切られています。もう一度ログインしてください。" 32 | 33 | #: lib/casserver/cas.rb:126 34 | msgid "You took too long to enter your credentials. Please try again." 35 | msgstr "" 36 | "クレデンシャルの入力に時間が掛かりすぎました。もう一度試してください。" 37 | 38 | #: lib/casserver/cas.rb:130 39 | msgid "" 40 | "The login ticket you provided is invalid. There may be a problem with the " 41 | "authentication system." 42 | msgstr "" 43 | "指定されたログインチケットが無効です。認証システムに問題があるようです。" 44 | 45 | #: lib/casserver/controllers.rb:32 46 | msgid "" 47 | "You are currently logged in as '%s'. If this is not you, please log in below." 48 | msgstr "" 49 | "'%s'としてログインしています。違うユーザーでログインするには下に入力してくだ" 50 | "さい。" 51 | 52 | #: lib/casserver/controllers.rb:37 53 | msgid "" 54 | "The client and server are unable to negotiate authentication. Please try " 55 | "logging in again later." 56 | msgstr "" 57 | "クライアントとサーバー間で認証ができませんでした。しばらくしてから再度ログイ" 58 | "ンしてください。" 59 | 60 | #: lib/casserver/controllers.rb:54 61 | msgid "" 62 | "The server cannot fulfill this gateway request because no service parameter " 63 | "was given." 64 | msgstr "" 65 | "サービスパラメーターが指定されていないので、サーバーはゲートウェイリクエスト" 66 | "を満たす事ができません。" 67 | 68 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 69 | msgid "" 70 | "The target service your browser supplied appears to be invalid. Please " 71 | "contact your system administrator for help." 72 | msgstr "" 73 | "ブラウザが示す対象サービスは無効のようです。システム管理者に連絡してくださ" 74 | "い。" 75 | 76 | #: lib/casserver/controllers.rb:88 77 | msgid "" 78 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 79 | "with your request." 80 | msgstr "" 81 | "CASのURIを推測することができませんでした。リクエストにsubmitToURIパラメータを" 82 | "指定してください。" 83 | 84 | #: lib/casserver/controllers.rb:168 85 | msgid "You have successfully logged in." 86 | msgstr "ログインしました" 87 | 88 | #: lib/casserver/controllers.rb:184 89 | msgid "Incorrect username or password." 90 | msgstr "ユーザー名またはパスワードが間違っています" 91 | 92 | #: lib/casserver/controllers.rb:267 93 | msgid "You have successfully logged out." 94 | msgstr "ログアウトしました。" 95 | 96 | #: lib/casserver/controllers.rb:269 97 | msgid " Please click on the following link to continue:" 98 | msgstr " 継続するには、以下のリンクをクリックしてください:" 99 | 100 | #: lib/casserver/controllers.rb:419 101 | msgid "To generate a login ticket, you must make a POST request." 102 | msgstr "ログインチケットを発行するには、POSTリクエストを送る必要があります。" 103 | 104 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 105 | msgid " Central Login" 106 | msgstr " 統合ログイン" 107 | 108 | #: lib/casserver/views.rb:68 109 | msgid "Please wait..." 110 | msgstr "" 111 | 112 | #: lib/casserver/views.rb:74 113 | msgid "Username" 114 | msgstr "ユーザー名" 115 | 116 | #: lib/casserver/views.rb:83 117 | msgid "Password" 118 | msgstr "パスワード" 119 | 120 | #: lib/casserver/views.rb:92 121 | msgid "Remeber me on this computer" 122 | msgstr "" 123 | 124 | #: lib/casserver/views.rb:101 125 | msgid "LOGIN" 126 | msgstr "ログイン" 127 | -------------------------------------------------------------------------------- /po/pl_PL/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Polish translations for RubyCAS-Server package 2 | # Polskie tłumaczenia dla pakietu RubyCAS-Server. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Matt Zukowski , 2008. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-11-12 11:03-0500\n" 12 | "Last-Translator: Matt Zukowski \n" 13 | "Language-Team: Polish\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " 18 | "|| n%100>=20) ? 1 : 2);\n" 19 | 20 | #: lib/casserver/cas.rb:117 21 | msgid "" 22 | "Your login request did not include a login ticket. There may be a problem " 23 | "with the authentication system." 24 | msgstr "" 25 | 26 | #: lib/casserver/cas.rb:121 27 | msgid "" 28 | "The login ticket you provided has already been used up. Please try logging " 29 | "in again." 30 | msgstr "" 31 | 32 | #: lib/casserver/cas.rb:126 33 | msgid "You took too long to enter your credentials. Please try again." 34 | msgstr "" 35 | 36 | #: lib/casserver/cas.rb:130 37 | msgid "" 38 | "The login ticket you provided is invalid. There may be a problem with the " 39 | "authentication system." 40 | msgstr "" 41 | 42 | #: lib/casserver/controllers.rb:32 43 | msgid "" 44 | "You are currently logged in as '%s'. If this is not you, please log in below." 45 | msgstr "" 46 | "Jesteś aktualnie zalogowany jako '%s'. Jeżeli to nie jesteś ty, zaloguj się " 47 | "tutaj." 48 | 49 | #: lib/casserver/controllers.rb:37 50 | msgid "" 51 | "The client and server are unable to negotiate authentication. Please try " 52 | "logging in again later." 53 | msgstr "" 54 | "Klient i serwer nie są w stanie negocjować uwierzytelniania. Proszę " 55 | "spróbować zalogować się ponownie później." 56 | 57 | #: lib/casserver/controllers.rb:54 58 | msgid "" 59 | "The server cannot fulfill this gateway request because no service parameter " 60 | "was given." 61 | msgstr "" 62 | "Serwer nie może spełnić tego żądania bramowego, ponieważ nie został podany " 63 | "parametr usługi." 64 | 65 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 66 | msgid "" 67 | "The target service your browser supplied appears to be invalid. Please " 68 | "contact your system administrator for help." 69 | msgstr "" 70 | "Podany adresat usługi wydaje się nieprawidłowy. Skontaktuj się z " 71 | "administratorem systemu żeby uzyskać pomocy." 72 | 73 | #: lib/casserver/controllers.rb:88 74 | msgid "" 75 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 76 | "with your request." 77 | msgstr "" 78 | "Nie można odgadnąć URI do logowania do CAS. Proszę dostarczyć parametr " 79 | "submitToURI." 80 | 81 | #: lib/casserver/controllers.rb:168 82 | msgid "You have successfully logged in." 83 | msgstr "Jesteś zalogowany." 84 | 85 | #: lib/casserver/controllers.rb:184 86 | msgid "Incorrect username or password." 87 | msgstr "Niepoprawny użytkownik lub hasło." 88 | 89 | #: lib/casserver/controllers.rb:267 90 | msgid "You have successfully logged out." 91 | msgstr "Jesteś wylogowany." 92 | 93 | #: lib/casserver/controllers.rb:269 94 | msgid " Please click on the following link to continue:" 95 | msgstr " Proszę kliknąć na poniższy link, aby kontynuować:" 96 | 97 | #: lib/casserver/controllers.rb:419 98 | msgid "To generate a login ticket, you must make a POST request." 99 | msgstr "Aby wygenerować login bilet, musisz złożyć żądanie POST." 100 | 101 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 102 | msgid " Central Login" 103 | msgstr " Centralna Usługa Uwierzytelniania" 104 | 105 | #: lib/casserver/views.rb:68 106 | msgid "Please wait..." 107 | msgstr "Chwileczke..." 108 | 109 | #: lib/casserver/views.rb:74 110 | msgid "Username" 111 | msgstr "Użytkownik" 112 | 113 | #: lib/casserver/views.rb:83 114 | msgid "Password" 115 | msgstr "Hasło" 116 | 117 | #: lib/casserver/views.rb:92 118 | msgid "Remeber me on this computer" 119 | msgstr "" 120 | 121 | #: lib/casserver/views.rb:101 122 | msgid "LOGIN" 123 | msgstr "ZALOGUJ" 124 | -------------------------------------------------------------------------------- /po/pt_BR/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Brazilian Portuguese translations for RubyCAS-Server package 2 | # Traduções em Português do Brasil para o pacote RubyCAS-Server. 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Kivanio Barbosa , 2009. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2009-03-17 20:55+0200\n" 12 | "Last-Translator: Kivanio Barbosa \n" 13 | "Language-Team: Brazil\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "" 45 | "Você está logado como '%s'. Se este não for você, Por favor, faça o login a " 46 | "baixo." 47 | 48 | #: lib/casserver/controllers.rb:37 49 | msgid "" 50 | "The client and server are unable to negotiate authentication. Please try " 51 | "logging in again later." 52 | msgstr "" 53 | "O cliente e o servidor não puderam efetuar a autenticação. Por favor, tente " 54 | "novamente mais tarde." 55 | 56 | #: lib/casserver/controllers.rb:54 57 | msgid "" 58 | "The server cannot fulfill this gateway request because no service parameter " 59 | "was given." 60 | msgstr "" 61 | "O servidor não pode completar a solicitação porque não foi enviado o " 62 | "paramêtro do serviço." 63 | 64 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 65 | msgid "" 66 | "The target service your browser supplied appears to be invalid. Please " 67 | "contact your system administrator for help." 68 | msgstr "" 69 | "O seu navegador está aparentemente com problemas. Por favor, contate o " 70 | "administrador do sistema para obter ajuda." 71 | 72 | #: lib/casserver/controllers.rb:88 73 | msgid "" 74 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 75 | "with your request." 76 | msgstr "" 77 | "Não encontramos a URI de acesso ao CAS. Por favor, informe corretamente no " 78 | "submitToURI com sua solicitação." 79 | 80 | #: lib/casserver/controllers.rb:168 81 | msgid "You have successfully logged in." 82 | msgstr "Login efetuado com sucesso." 83 | 84 | #: lib/casserver/controllers.rb:184 85 | msgid "Incorrect username or password." 86 | msgstr "Usuário ou Senha está incorreto." 87 | 88 | #: lib/casserver/controllers.rb:267 89 | msgid "You have successfully logged out." 90 | msgstr "Você saiu do sistema com sucesso." 91 | 92 | #: lib/casserver/controllers.rb:269 93 | msgid " Please click on the following link to continue:" 94 | msgstr " Por favor, clique no seguinte link para continuar:" 95 | 96 | #: lib/casserver/controllers.rb:419 97 | msgid "To generate a login ticket, you must make a POST request." 98 | msgstr "" 99 | "Para gerar um ticket de acceso, você deve fazer uma requisição via POST." 100 | 101 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 102 | msgid " Central Login" 103 | msgstr " Central de Autenticação" 104 | 105 | #: lib/casserver/views.rb:68 106 | msgid "Please wait..." 107 | msgstr "" 108 | 109 | #: lib/casserver/views.rb:74 110 | msgid "Username" 111 | msgstr "Usuário" 112 | 113 | #: lib/casserver/views.rb:83 114 | msgid "Password" 115 | msgstr "Senha" 116 | 117 | #: lib/casserver/views.rb:92 118 | msgid "Remeber me on this computer" 119 | msgstr "" 120 | 121 | #: lib/casserver/views.rb:101 122 | msgid "LOGIN" 123 | msgstr "ENTRAR" 124 | -------------------------------------------------------------------------------- /po/ru_RU/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Russian translation for Rubycas server. 2 | # Copyright (C) Matt Zukowski 3 | # This file is distributed under the same license as the rubycas-server package. 4 | # Antono Vasiljev , 2008. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: rubycas-server \n" 9 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 10 | "PO-Revision-Date: 2008-11-04 12:32+0200\n" 11 | "Last-Translator: Antono Vasiljev \n" 12 | "Language-Team: Russian \n" 13 | "MIME-Version: 1.0\n" 14 | "Content-Type: text/plain; charset=UTF-8\n" 15 | "Content-Transfer-Encoding: 8bit\n" 16 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 17 | 18 | #: lib/casserver/cas.rb:117 19 | msgid "" 20 | "Your login request did not include a login ticket. There may be a problem " 21 | "with the authentication system." 22 | msgstr "" 23 | 24 | #: lib/casserver/cas.rb:121 25 | msgid "" 26 | "The login ticket you provided has already been used up. Please try logging " 27 | "in again." 28 | msgstr "" 29 | 30 | #: lib/casserver/cas.rb:126 31 | msgid "You took too long to enter your credentials. Please try again." 32 | msgstr "" 33 | 34 | #: lib/casserver/cas.rb:130 35 | msgid "" 36 | "The login ticket you provided is invalid. There may be a problem with the " 37 | "authentication system." 38 | msgstr "" 39 | 40 | #: lib/casserver/controllers.rb:32 41 | msgid "" 42 | "You are currently logged in as '%s'. If this is not you, please log in below." 43 | msgstr "Вы авторизированы как '%s'." 44 | 45 | #: lib/casserver/controllers.rb:37 46 | msgid "" 47 | "The client and server are unable to negotiate authentication. Please try " 48 | "logging in again later." 49 | msgstr "" 50 | "Клиент и сервер не могут провести проверку прав. Попробуйте войти позже." 51 | 52 | #: lib/casserver/controllers.rb:54 53 | msgid "" 54 | "The server cannot fulfill this gateway request because no service parameter " 55 | "was given." 56 | msgstr "" 57 | "Этот сервер не может выполнить этот запрос, поскольку не были указаны " 58 | "праметры сервиса." 59 | 60 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 61 | msgid "" 62 | "The target service your browser supplied appears to be invalid. Please " 63 | "contact your system administrator for help." 64 | msgstr "" 65 | "Сервис, указанный вашим браузером, неверен. Свяжитесь с вашим системным " 66 | "администратором." 67 | 68 | #: lib/casserver/controllers.rb:88 69 | msgid "" 70 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 71 | "with your request." 72 | msgstr "" 73 | "Невозможно угадать адрес входа на CAS. Пожалуйста, передайте с запросом " 74 | "параметр submitToURI." 75 | 76 | #: lib/casserver/controllers.rb:168 77 | msgid "You have successfully logged in." 78 | msgstr "Вы успешно вошли." 79 | 80 | #: lib/casserver/controllers.rb:184 81 | msgid "Incorrect username or password." 82 | msgstr "Неверное имя пользователя или пароль." 83 | 84 | #: lib/casserver/controllers.rb:267 85 | msgid "You have successfully logged out." 86 | msgstr "Вы успешно вышли." 87 | 88 | #: lib/casserver/controllers.rb:269 89 | msgid " Please click on the following link to continue:" 90 | msgstr " Перейдите по ссылке чтобы продолжить: " 91 | 92 | #: lib/casserver/controllers.rb:419 93 | msgid "To generate a login ticket, you must make a POST request." 94 | msgstr "Чтобы сгенерировать входной билет вы должны делать POST запрос." 95 | 96 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 97 | msgid " Central Login" 98 | msgstr " Центральный вход" 99 | 100 | #: lib/casserver/views.rb:68 101 | msgid "Please wait..." 102 | msgstr "Подождите..." 103 | 104 | #: lib/casserver/views.rb:74 105 | msgid "Username" 106 | msgstr "Логин" 107 | 108 | #: lib/casserver/views.rb:83 109 | msgid "Password" 110 | msgstr "Пароль" 111 | 112 | #: lib/casserver/views.rb:92 113 | msgid "Remeber me on this computer" 114 | msgstr "" 115 | 116 | #: lib/casserver/views.rb:101 117 | msgid "LOGIN" 118 | msgstr "Войти" 119 | -------------------------------------------------------------------------------- /po/rubycas-server.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2009 of The Contributors (see project history on github.com) 3 | # This file is distributed under the same license as the RubyCAS-Server package. 4 | # Matt Zukowski, 2009. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2008-10-29 20:55+0200\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "" 45 | 46 | #: lib/casserver/controllers.rb:37 47 | msgid "" 48 | "The client and server are unable to negotiate authentication. Please try " 49 | "logging in again later." 50 | msgstr "" 51 | 52 | #: lib/casserver/controllers.rb:54 53 | msgid "" 54 | "The server cannot fulfill this gateway request because no service parameter " 55 | "was given." 56 | msgstr "" 57 | 58 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 59 | msgid "" 60 | "The target service your browser supplied appears to be invalid. Please " 61 | "contact your system administrator for help." 62 | msgstr "" 63 | 64 | #: lib/casserver/controllers.rb:88 65 | msgid "" 66 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 67 | "with your request." 68 | msgstr "" 69 | 70 | #: lib/casserver/controllers.rb:168 71 | msgid "You have successfully logged in." 72 | msgstr "" 73 | 74 | #: lib/casserver/controllers.rb:184 75 | msgid "Incorrect username or password." 76 | msgstr "" 77 | 78 | #: lib/casserver/controllers.rb:267 79 | msgid "You have successfully logged out." 80 | msgstr "" 81 | 82 | #: lib/casserver/controllers.rb:269 83 | msgid " Please click on the following link to continue:" 84 | msgstr "" 85 | 86 | #: lib/casserver/controllers.rb:419 87 | msgid "To generate a login ticket, you must make a POST request." 88 | msgstr "" 89 | 90 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 91 | msgid " Central Login" 92 | msgstr "" 93 | 94 | #: lib/casserver/views.rb:68 95 | msgid "Please wait..." 96 | msgstr "" 97 | 98 | #: lib/casserver/views.rb:74 99 | msgid "Username" 100 | msgstr "" 101 | 102 | #: lib/casserver/views.rb:83 103 | msgid "Password" 104 | msgstr "" 105 | 106 | #: lib/casserver/views.rb:92 107 | msgid "Remeber me on this computer" 108 | msgstr "" 109 | 110 | #: lib/casserver/views.rb:101 111 | msgid "LOGIN" 112 | msgstr "" 113 | -------------------------------------------------------------------------------- /po/zh_CN/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Simplified Chinese translations for RubyCAS-Server package 2 | # RubyCAS-Server 的简体中文翻译。 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # hgf , 2010. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2009-03-17 20:55+0200\n" 12 | "Last-Translator: hgf \n" 13 | "Language-Team: Simplified Chinese\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "你的登录请求没包含登录凭证,这可能是认证系统的问题" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "你提供的登录凭证已经使用过了,请重新登录" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "你的认证花了太长时间,请重新认证" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "你所提供的登录凭证是无效的,这可能是认证系统的问题" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "你正以 '%s' 的身份登入。如果这不是你,请重新登录" 45 | 46 | #: lib/casserver/controllers.rb:37 47 | msgid "" 48 | "The client and server are unable to negotiate authentication. Please try " 49 | "logging in again later." 50 | msgstr "现在无法认证,请稍后重试" 51 | 52 | #: lib/casserver/controllers.rb:54 53 | msgid "" 54 | "The server cannot fulfill this gateway request because no service parameter " 55 | "was given." 56 | msgstr "无法完成网关请求,因为没有提供服务的参数" 57 | 58 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 59 | msgid "" 60 | "The target service your browser supplied appears to be invalid. Please " 61 | "contact your system administrator for help." 62 | msgstr "你的浏览器提供的网址是无效的,请联系你的系统管理员" 63 | 64 | #: lib/casserver/controllers.rb:88 65 | msgid "" 66 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 67 | "with your request." 68 | msgstr "无法判断 CAS 的登录地址。请提供 submitToURI 的参数" 69 | 70 | #: lib/casserver/controllers.rb:168 71 | msgid "You have successfully logged in." 72 | msgstr "你成功登录了" 73 | 74 | #: lib/casserver/controllers.rb:184 75 | msgid "Incorrect username or password." 76 | msgstr "错误的帐号或密码" 77 | 78 | #: lib/casserver/controllers.rb:267 79 | msgid "You have successfully logged out." 80 | msgstr "你成功登出了" 81 | 82 | #: lib/casserver/controllers.rb:269 83 | msgid " Please click on the following link to continue:" 84 | msgstr " 请点击下列连接继续" 85 | 86 | #: lib/casserver/controllers.rb:419 87 | msgid "To generate a login ticket, you must make a POST request." 88 | msgstr "你必须使用 POST 来产生登录凭证" 89 | 90 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 91 | msgid " Central Login" 92 | msgstr " 整合登录" 93 | 94 | #: lib/casserver/views.rb:68 95 | msgid "Please wait..." 96 | msgstr "请稍候..." 97 | 98 | #: lib/casserver/views.rb:74 99 | msgid "Username" 100 | msgstr "用户名" 101 | 102 | #: lib/casserver/views.rb:83 103 | msgid "Password" 104 | msgstr "密码" 105 | 106 | #: lib/casserver/views.rb:92 107 | msgid "Remeber me on this computer" 108 | msgstr "记住我" 109 | 110 | #: lib/casserver/views.rb:101 111 | msgid "LOGIN" 112 | msgstr "登录" 113 | 114 | -------------------------------------------------------------------------------- /po/zh_TW/rubycas-server.po: -------------------------------------------------------------------------------- 1 | # Traditional Chinese translations for RubyCAS-Server package 2 | # RubyCAS-Server 的正體中文翻譯。 3 | # Copyright (C) 2008 THE RubyCAS-Server'S COPYRIGHT HOLDER 4 | # This file is distributed under the same license as the RubyCAS-Server package. 5 | # Lin Jen-Shin , 2009. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: rubycas-server \n" 10 | "POT-Creation-Date: 2009-09-29 17:04+0800\n" 11 | "PO-Revision-Date: 2009-03-17 20:55+0200\n" 12 | "Last-Translator: Lin Jen-Shin \n" 13 | "Language-Team: Traditional Chinese\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 18 | 19 | #: lib/casserver/cas.rb:117 20 | msgid "" 21 | "Your login request did not include a login ticket. There may be a problem " 22 | "with the authentication system." 23 | msgstr "你沒有傳送登入憑証,這可能是認證系統的問題" 24 | 25 | #: lib/casserver/cas.rb:121 26 | msgid "" 27 | "The login ticket you provided has already been used up. Please try logging " 28 | "in again." 29 | msgstr "你所提供的登入憑証已經被使用過了,請重新登入" 30 | 31 | #: lib/casserver/cas.rb:126 32 | msgid "You took too long to enter your credentials. Please try again." 33 | msgstr "你的認證花了太多時間,請再試一次" 34 | 35 | #: lib/casserver/cas.rb:130 36 | msgid "" 37 | "The login ticket you provided is invalid. There may be a problem with the " 38 | "authentication system." 39 | msgstr "你所傳送的登入憑証是無效的,這可能是認證系統的問題" 40 | 41 | #: lib/casserver/controllers.rb:32 42 | msgid "" 43 | "You are currently logged in as '%s'. If this is not you, please log in below." 44 | msgstr "你正以 '%s' 的身分登入。如果這不是你,請重新登入" 45 | 46 | #: lib/casserver/controllers.rb:37 47 | msgid "" 48 | "The client and server are unable to negotiate authentication. Please try " 49 | "logging in again later." 50 | msgstr "現在無法認證,請稍候再嘗試登入" 51 | 52 | #: lib/casserver/controllers.rb:54 53 | msgid "" 54 | "The server cannot fulfill this gateway request because no service parameter " 55 | "was given." 56 | msgstr "無法完成 gateway request 因為沒有提供 service 的參數" 57 | 58 | #: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179 59 | msgid "" 60 | "The target service your browser supplied appears to be invalid. Please " 61 | "contact your system administrator for help." 62 | msgstr "你的瀏覽器傳送的服務網址是無效的,請向你的系統管理員尋求協助" 63 | 64 | #: lib/casserver/controllers.rb:88 65 | msgid "" 66 | "Could not guess the CAS login URI. Please supply a submitToURI parameter " 67 | "with your request." 68 | msgstr "無法判斷 CAS 的登入網址。請提供 submitToURI 的參數" 69 | 70 | #: lib/casserver/controllers.rb:168 71 | msgid "You have successfully logged in." 72 | msgstr "你成功登入了" 73 | 74 | #: lib/casserver/controllers.rb:184 75 | msgid "Incorrect username or password." 76 | msgstr "你所輸入的帳號或是密碼是錯誤的" 77 | 78 | #: lib/casserver/controllers.rb:267 79 | msgid "You have successfully logged out." 80 | msgstr "你成功登出了" 81 | 82 | #: lib/casserver/controllers.rb:269 83 | msgid " Please click on the following link to continue:" 84 | msgstr " 請點以下的連結繼續" 85 | 86 | #: lib/casserver/controllers.rb:419 87 | msgid "To generate a login ticket, you must make a POST request." 88 | msgstr "你必須使用 POST 來產生登入憑証" 89 | 90 | #: lib/casserver/views.rb:43 lib/casserver/views.rb:120 91 | msgid " Central Login" 92 | msgstr " 整合登入" 93 | 94 | #: lib/casserver/views.rb:68 95 | msgid "Please wait..." 96 | msgstr "請稍候..." 97 | 98 | #: lib/casserver/views.rb:74 99 | msgid "Username" 100 | msgstr "帳號" 101 | 102 | #: lib/casserver/views.rb:83 103 | msgid "Password" 104 | msgstr "密碼" 105 | 106 | #: lib/casserver/views.rb:92 107 | msgid "Remeber me on this computer" 108 | msgstr "在這台電腦上記住我" 109 | 110 | #: lib/casserver/views.rb:101 111 | msgid "LOGIN" 112 | msgstr "登入" 113 | 114 | -------------------------------------------------------------------------------- /public/themes/cas.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: Verdana, sans-serif; 3 | } 4 | 5 | body { 6 | text-align: center; /* hack for IE */ 7 | } 8 | 9 | label { 10 | font-weight: bold; 11 | font-size: 9px; 12 | } 13 | 14 | input { 15 | font-weight: normal; 16 | font-size: 12px; 17 | } 18 | 19 | input.button { 20 | /*font-weight: bold;*/ 21 | font-size: 10px; 22 | } 23 | 24 | #login-box { 25 | margin: 0 auto; 26 | width: 350px; 27 | top: 130px; 28 | position: relative; 29 | } 30 | 31 | #headline-container { 32 | text-align: right; 33 | border-bottom: 1px solid #899989; 34 | font-family: Tahoma, Verdana, sans-serif; 35 | font-size: 22px; 36 | margin-right: 0px; 37 | padding-right: 7px; 38 | margin-left: 10px; 39 | letter-spacing: -0.25px; 40 | } 41 | 42 | #logo-container { 43 | vertical-align: top; 44 | } 45 | 46 | #logo { 47 | } 48 | 49 | #login-form-container { 50 | vertical-align: top; 51 | } 52 | 53 | 54 | #username, 55 | #password { 56 | width: 10em; 57 | } 58 | 59 | #login-form { 60 | padding: 20px; 61 | } 62 | 63 | 64 | #form-layout { 65 | position: relative; 66 | top: 6px; 67 | width: 100%; 68 | } 69 | 70 | #form-layout td { 71 | text-align: center; 72 | padding-bottom: 8px; 73 | } 74 | 75 | #form-layout td#submit-container { 76 | text-align: right; 77 | padding-right: 10px; 78 | } 79 | 80 | #infoline { 81 | font-size: 9px; 82 | } 83 | 84 | #messagebox-container { 85 | padding-left: 11px; 86 | padding-right: 16px; 87 | } 88 | 89 | div.messagebox { 90 | font-size: 12px; 91 | padding: 5px; 92 | padding-left: 55px; 93 | text-align: center; 94 | width: 70%; 95 | min-height: 34px; 96 | vertical-align: middle; 97 | } 98 | 99 | div.mistake { 100 | color: #d00; 101 | background-image: url(warning.png); 102 | background-repeat: no-repeat; 103 | background-position: 10px 5px; 104 | font-weight: bold; 105 | } 106 | 107 | div.confirmation { 108 | color: #280; 109 | background-image: url(ok.png); 110 | background-repeat: no-repeat; 111 | background-position: 10px 5px; 112 | font-weight: bold; 113 | } 114 | 115 | div.notice { 116 | color: #04c; 117 | background-image: url(notice.png); 118 | background-repeat: no-repeat; 119 | background-position: 10px 5px; 120 | font-weight: bold; 121 | } 122 | -------------------------------------------------------------------------------- /public/themes/notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/notice.png -------------------------------------------------------------------------------- /public/themes/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/ok.png -------------------------------------------------------------------------------- /public/themes/simple/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/simple/bg.png -------------------------------------------------------------------------------- /public/themes/simple/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/simple/favicon.png -------------------------------------------------------------------------------- /public/themes/simple/login_box_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/simple/login_box_bg.png -------------------------------------------------------------------------------- /public/themes/simple/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/simple/logo.png -------------------------------------------------------------------------------- /public/themes/simple/theme.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url(bg.png); 3 | } 4 | 5 | #headline-container { 6 | margin-bottom: 5px; 7 | } 8 | 9 | #login-box { 10 | margin: 0 auto; 11 | width: 450px; 12 | top: 110px; 13 | position: relative; 14 | } 15 | 16 | #login-form { 17 | background-color: #fff; 18 | border: 1px #aaa solid; 19 | } 20 | 21 | #logo-container { 22 | vertical-align: middle; 23 | } 24 | 25 | #logo { 26 | width: 128px; 27 | height: 128px; 28 | } 29 | -------------------------------------------------------------------------------- /public/themes/urbacon/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/urbacon/bg.png -------------------------------------------------------------------------------- /public/themes/urbacon/login_box_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/urbacon/login_box_bg.png -------------------------------------------------------------------------------- /public/themes/urbacon/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/urbacon/logo.png -------------------------------------------------------------------------------- /public/themes/urbacon/theme.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url(bg.png); 3 | } 4 | 5 | label { 6 | color: #5c6156; 7 | } 8 | 9 | #login-form { 10 | background-repeat: no-repeat; 11 | background-image: url(login_box_bg.png); 12 | height: 175px; 13 | width: 210px; 14 | padding: 20px; 15 | } 16 | 17 | #logo-container { 18 | vertical-align: top; 19 | } 20 | 21 | #logo { 22 | width: 115px; 23 | height: 171px; 24 | } 25 | 26 | #infoline { 27 | color: #5c6156; 28 | font-size: 8px; 29 | } 30 | 31 | #headline-container { 32 | margin-right: 15px; 33 | } 34 | -------------------------------------------------------------------------------- /public/themes/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/public/themes/warning.png -------------------------------------------------------------------------------- /resources/diagrams/basic_cas_single_signon_mechanism_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunark/rubycas-server/3595eae24605df63086cade3316d49520f6a2775/resources/diagrams/basic_cas_single_signon_mechanism_diagram.png -------------------------------------------------------------------------------- /resources/init.d.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # Copyright (c) 2008 Urbacon Ltd. 4 | # 5 | # System startup script for the RubyCAS-Server 6 | # 7 | # Instructions: 8 | # 1. Rename this file to 'rubycas-server' 9 | # 2. Copy it to your '/etc/init.d' directory 10 | # 3. chmod +x /etc/init.d/rubycas-server 11 | # 12 | # chkconfig - 85 15 13 | # description: Provides single-sign-on authentication for web applications. 14 | # 15 | ### BEGIN INIT INFO 16 | # Provides: rubycas-server 17 | # Required-Start: $syslog 18 | # Should-Start: 19 | # Required-Stop: $syslog 20 | # Should-Stop: 21 | # Default-Start: 3 5 22 | # Default-Stop: 0 1 2 6 23 | # Description: Start the RubyCAS-Server 24 | ### END INIT INFO 25 | 26 | CASSERVER_CTL=rubycas-server-ctl 27 | 28 | # Gracefully exit if the controller is missing. 29 | which $CASSERVER_CTL > /dev/null || exit 0 30 | 31 | # Source config 32 | . /etc/rc.status 33 | 34 | rc_reset 35 | case "$1" in 36 | start) 37 | $CASSERVER_CTL start 38 | rc_status -v 39 | ;; 40 | stop) 41 | $CASSERVER_CTL stop 42 | rc_status -v 43 | ;; 44 | restart) 45 | $0 stop 46 | $0 start 47 | rc_status 48 | ;; 49 | status) 50 | $CASSERVER_CTL status 51 | rc_status -v 52 | ;; 53 | *) 54 | echo "Usage: $0 {start|stop|status|restart}" 55 | exit 1 56 | ;; 57 | esac 58 | rc_exit 59 | -------------------------------------------------------------------------------- /rubycas-server.gemspec: -------------------------------------------------------------------------------- 1 | 2 | $gemspec = Gem::Specification.new do |s| 3 | s.name = 'rubycas-server' 4 | s.version = '1.0' 5 | s.authors = ["Matt Zukowski"] 6 | s.email = ["matt@zukowski.ca"] 7 | s.homepage = 'http://code.google.com/p/rubycas-server/' 8 | s.platform = Gem::Platform::RUBY 9 | s.summary = %q{Provides single sign-on authentication for web applications using the CAS protocol.} 10 | s.description = %q{Provides single sign-on authentication for web applications using the CAS protocol.} 11 | 12 | s.files = [ 13 | "CHANGELOG", "LICENSE", "README.md", "Rakefile", "setup.rb", 14 | "bin/*", "db/*", "lib/**/*.rb", "public/**/*", "po/**/*", "mo/**/*", "resources/*.*", 15 | "config.ru", "config/**/*", "tasks/**/*.rake", "vendor/**/*", "script/*", "lib/**/*.erb", "lib/**/*.builder", 16 | "Gemfile", "rubycas-server.gemspec" 17 | ].map{|p| Dir[p]}.flatten 18 | 19 | s.test_files = `git ls-files -- spec`.split("\n") 20 | 21 | s.executables = ["rubycas-server"] 22 | s.bindir = "bin" 23 | s.require_path = "lib" 24 | 25 | s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md"] 26 | 27 | s.has_rdoc = true 28 | s.post_install_message = %q{ 29 | For more information on RubyCAS-Server, see http://code.google.com/p/rubycas-server 30 | 31 | If you plan on using RubyCAS-Server with languages other than English, please cd into the 32 | RubyCAS-Server installation directory (where the gem is installed) and type `rake localization:mo` 33 | to build the LOCALE_LC files. 34 | 35 | } 36 | 37 | s.add_dependency("activerecord", "~> 2.3.12") 38 | s.add_dependency("activesupport", "~> 2.3.12") 39 | s.add_dependency("sinatra", "~> 1.0") 40 | s.add_dependency("gettext", "~> 2.1.0") 41 | s.add_dependency("crypt-isaac", "~> 0.9.1") 42 | 43 | s.add_development_dependency("rack-test") 44 | s.add_development_dependency("capybara") 45 | s.add_development_dependency("rspec") 46 | s.add_development_dependency("rspec-core") 47 | s.add_development_dependency("sqlite3", "~> 1.3.1") 48 | 49 | # for authenticator specs 50 | s.add_development_dependency("net-ldap", "~> 0.1.1") 51 | s.add_development_dependency("activeresource", "~> 2.3.12") 52 | 53 | s.rdoc_options = [ 54 | '--quiet', '--title', 'RubyCAS-Server Documentation', '--opname', 55 | 'index.html', '--line-numbers', '--main', 'README.md', '--inline-source' 56 | ] 57 | end 58 | -------------------------------------------------------------------------------- /spec/alt_config.yml: -------------------------------------------------------------------------------- 1 | server: webrick 2 | port: 6543 3 | #ssl_cert: test.pem 4 | uri_path: /test 5 | #bind_address: 0.0.0.0 6 | 7 | # database: 8 | # adapter: mysql 9 | # database: casserver 10 | # username: root 11 | # password: 12 | # host: localhost 13 | # reconnect: true 14 | database: 15 | adapter: sqlite3 16 | database: spec/casserver_spec.db 17 | 18 | disable_auto_migrations: true 19 | 20 | quiet: true 21 | 22 | authenticator: 23 | class: CASServer::Authenticators::Test 24 | password: spec_password 25 | 26 | theme: simple 27 | 28 | organization: "RSPEC-TEST" 29 | 30 | infoline: "This is an rspec test." 31 | 32 | #custom_views: /path/to/custom/views 33 | 34 | default_locale: en 35 | 36 | log: 37 | file: casserver_spec.log 38 | level: DEBUG 39 | 40 | #db_log: 41 | # file: casserver_spec_db.log 42 | 43 | enable_single_sign_out: true 44 | 45 | #maximum_unused_login_ticket_lifetime: 300 46 | #maximum_unused_service_ticket_lifetime: 300 47 | 48 | #maximum_session_lifetime: 172800 49 | 50 | #downcase_username: true 51 | -------------------------------------------------------------------------------- /spec/authenticators/active_resource_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.dirname(__FILE__) + '/../spec_helper' 3 | 4 | require 'casserver/authenticators/active_resource' 5 | 6 | describe CASServer::Authenticators::Helpers::Identity do 7 | 8 | it { should be_an ActiveResource::Base } 9 | 10 | it "class should respond to :authenticate" do 11 | subject.class.should respond_to :authenticate 12 | end 13 | 14 | it "class should have a method_name accessor" do 15 | CASServer::Authenticators::Helpers::Identity.method_name.should == :authenticate 16 | end 17 | 18 | it "class should have a method_name accessor" do 19 | CASServer::Authenticators::Helpers::Identity.method_type.should == :post 20 | end 21 | 22 | it "class method_type accessor should validate type" do 23 | expect { 24 | CASServer::Authenticators::Helpers::Identity.method_type = :foo 25 | }.to raise_error(ArgumentError) 26 | end 27 | 28 | end 29 | 30 | describe CASServer::Authenticators::ActiveResource do 31 | 32 | describe "#setup" do 33 | 34 | it "should configure the identity object" do 35 | CASServer::Authenticators::Helpers::Identity.should_receive(:user=).with('httpuser').once 36 | CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :user => 'httpuser' 37 | end 38 | 39 | it "should configure the method_type" do 40 | CASServer::Authenticators::Helpers::Identity.should_receive(:method_type=).with('get').once 41 | CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :method_type => 'get' 42 | end 43 | 44 | it "should raise if site option is missing" do 45 | expect { 46 | CASServer::Authenticators::ActiveResource.setup({}).should 47 | }.to raise_error(CASServer::AuthenticatorError, /site option/) 48 | end 49 | end 50 | 51 | describe "#validate" do 52 | 53 | let(:credentials) { {:username => 'validusername', 54 | :password => 'validpassword', 55 | :service => 'test.service'} } 56 | 57 | let(:auth) { CASServer::Authenticators::ActiveResource.new } 58 | 59 | def mock_authenticate identity = nil 60 | identity = CASServer::Authenticators::Helpers::Identity.new if identity.nil? 61 | CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_return(identity) 62 | end 63 | 64 | def sample_identity attrs = {} 65 | identity = CASServer::Authenticators::Helpers::Identity.new 66 | attrs.each { |k,v| identity.send "#{k}=", v } 67 | identity 68 | end 69 | 70 | it "should call Identity#autenticate with the given params" do 71 | CASServer::Authenticators::Helpers::Identity.should_receive(:authenticate).with(credentials).once 72 | auth.validate(credentials) 73 | end 74 | 75 | it "should return identity object attributes as extra attributes" do 76 | auth.configure({}.with_indifferent_access) 77 | identity = sample_identity({:email => 'foo@example.org'}) 78 | mock_authenticate identity 79 | auth.validate(credentials).should be_true 80 | auth.extra_attributes.should == identity.attributes 81 | end 82 | 83 | it "should return false when http raises" do 84 | CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_raise(ActiveResource::ForbiddenAccess.new({})) 85 | auth.validate(credentials).should be_false 86 | end 87 | 88 | it "should apply extra_attribute filter" do 89 | auth.configure({ :extra_attributes => 'age'}.with_indifferent_access) 90 | mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 }) 91 | auth.validate(credentials).should be_true 92 | auth.extra_attributes.should == { "age" => "28" } 93 | end 94 | 95 | it "should only extract not filtered attributes" do 96 | auth.configure({ :filter_attributes => 'age'}.with_indifferent_access) 97 | mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 }) 98 | auth.validate(credentials).should be_true 99 | auth.extra_attributes.should == { "email" => 'foo@example.org' } 100 | end 101 | 102 | it "should filter password if filter attributes is not given" do 103 | auth.configure({}.with_indifferent_access) 104 | mock_authenticate sample_identity({ :email => 'foo@example.org', :password => 'secret' }) 105 | auth.validate(credentials).should be_true 106 | auth.extra_attributes.should == { "email" => 'foo@example.org' } 107 | end 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /spec/authenticators/ldap_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.dirname(__FILE__) + '/../spec_helper' 3 | 4 | require 'casserver/authenticators/ldap' 5 | 6 | describe CASServer::Authenticators::LDAP do 7 | before do 8 | @ldap_entry = mock(Net::LDAP::Entry.new) 9 | @ldap_entry.stub!(:[]).and_return("Test") 10 | 11 | @ldap = mock(Net::LDAP) 12 | @ldap.stub!(:host=) 13 | @ldap.stub!(:port=) 14 | @ldap.stub!(:encryption) 15 | @ldap.stub!(:bind_as).and_return(true) 16 | @ldap.stub!(:authenticate).and_return(true) 17 | @ldap.stub!(:search).and_return([@ldap_entry]) 18 | 19 | Net::LDAP.stub!(:new).and_return(@ldap) 20 | end 21 | 22 | describe '#validate' do 23 | 24 | it 'validate with preauthentication and with extra attributes' do 25 | auth = CASServer::Authenticators::LDAP.new 26 | 27 | auth_config = HashWithIndifferentAccess.new( 28 | :ldap => { 29 | :host => "ad.example.net", 30 | :port => 389, 31 | :base => "dc=example,dc=net", 32 | :filter => "(objectClass=person)", 33 | :auth_user => "authenticator", 34 | :auth_password => "itsasecret" 35 | }, 36 | :extra_attributes => [:full_name, :address] 37 | ) 38 | 39 | auth.configure(auth_config.merge('auth_index' => 0)) 40 | auth.validate( 41 | :username => 'validusername', 42 | :password => 'validpassword', 43 | :service => 'test.service', 44 | :request => {} 45 | ).should == true 46 | 47 | auth.extra_attributes.should == {:full_name => 'Test', :address => 'Test'} 48 | end 49 | 50 | end 51 | end 52 | 53 | 54 | -------------------------------------------------------------------------------- /spec/casserver_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.dirname(__FILE__) + '/spec_helper' 3 | 4 | $LOG = Logger.new(File.basename(__FILE__).gsub('.rb','.log')) 5 | 6 | RSpec.configure do |config| 7 | config.include Capybara 8 | end 9 | 10 | VALID_USERNAME = 'spec_user' 11 | VALID_PASSWORD = 'spec_password' 12 | 13 | ATTACK_USERNAME = '%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E&password=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E<=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E&service=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E' 14 | INVALID_PASSWORD = 'invalid_password' 15 | 16 | describe 'CASServer' do 17 | 18 | before do 19 | @target_service = 'http://my.app.test' 20 | end 21 | 22 | describe "/login" do 23 | before do 24 | load_server(File.dirname(__FILE__) + "/default_config.yml") 25 | reset_spec_database 26 | end 27 | 28 | it "logs in successfully with valid username and password without a target service" do 29 | visit "/login" 30 | 31 | fill_in 'username', :with => VALID_USERNAME 32 | fill_in 'password', :with => VALID_PASSWORD 33 | click_button 'login-submit' 34 | 35 | page.should have_content("You have successfully logged in") 36 | end 37 | 38 | it "fails to log in with invalid password" do 39 | visit "/login" 40 | fill_in 'username', :with => VALID_USERNAME 41 | fill_in 'password', :with => INVALID_PASSWORD 42 | click_button 'login-submit' 43 | 44 | page.should have_content("Incorrect username or password") 45 | end 46 | 47 | it "logs in successfully with valid username and password and redirects to target service" do 48 | visit "/login?service="+CGI.escape(@target_service) 49 | 50 | fill_in 'username', :with => VALID_USERNAME 51 | fill_in 'password', :with => VALID_PASSWORD 52 | 53 | click_button 'login-submit' 54 | 55 | page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?\?ticket=ST\-[1-9rA-Z]+/ 56 | end 57 | 58 | it "preserves target service after invalid login" do 59 | visit "/login?service="+CGI.escape(@target_service) 60 | 61 | fill_in 'username', :with => VALID_USERNAME 62 | fill_in 'password', :with => INVALID_PASSWORD 63 | click_button 'login-submit' 64 | 65 | page.should have_content("Incorrect username or password") 66 | page.should have_xpath('//input[@id="service"]', :value => @target_service) 67 | end 68 | 69 | it "uses appropriate localization when 'lang' prameter is given (make sure you've run `rake localization:mo` first!!)" do 70 | visit "/login?lang=pl" 71 | page.should have_content("Użytkownik") 72 | 73 | visit "/login?lang=pt_BR" 74 | page.should have_content("Usuário") 75 | 76 | visit "/login?lang=en" 77 | page.should have_content("Username") 78 | end 79 | 80 | it "is not vunerable to Cross Site Scripting" do 81 | visit '/login?service=%22%2F%3E%3cscript%3ealert%2832%29%3c%2fscript%3e' 82 | page.should_not have_content("alert(32)") 83 | page.should_not have_xpath("//script") 84 | #page.should have_xpath("") 85 | end 86 | 87 | end # describe '/login' 88 | 89 | 90 | describe '/logout' do 91 | 92 | before do 93 | load_server(File.dirname(__FILE__) + "/default_config.yml") 94 | reset_spec_database 95 | end 96 | 97 | it "logs out successfully" do 98 | visit "/logout" 99 | 100 | page.should have_content("You have successfully logged out") 101 | end 102 | 103 | it "logs out successfully and redirects to target service" do 104 | visit "/logout?gateway=true&service="+CGI.escape(@target_service) 105 | 106 | page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?/ 107 | end 108 | 109 | end # describe '/logout' 110 | 111 | describe 'Configuration' do 112 | it "uri_path value changes prefix of routes" do 113 | load_server(File.dirname(__FILE__) + "/alt_config.yml") 114 | @target_service = 'http://my.app.test' 115 | 116 | visit "/test/login" 117 | page.status_code.should_not == 404 118 | 119 | visit "/test/logout" 120 | page.status_code.should_not == 404 121 | end 122 | end 123 | 124 | describe "proxyValidate" do 125 | before do 126 | load_server(File.dirname(__FILE__) + "/default_config.yml") 127 | reset_spec_database 128 | 129 | visit "/login?service="+CGI.escape(@target_service) 130 | 131 | fill_in 'username', :with => VALID_USERNAME 132 | fill_in 'password', :with => VALID_PASSWORD 133 | 134 | click_button 'login-submit' 135 | 136 | page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?\?ticket=ST\-[1-9rA-Z]+/ 137 | @ticket = page.current_url.match(/ticket=(.*)$/)[1] 138 | end 139 | 140 | it "should have extra attributes in proper format" do 141 | visit "/serviceValidate?service=#{CGI.escape(@target_service)}&ticket=#{@ticket}" 142 | 143 | encoded_utf_string = "Ютф" # actual string is "Ютф" 144 | page.body.should match("#{encoded_utf_string}") 145 | page.body.should match("123.45") 146 | page.body.should match("Ютф") 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /spec/default_config.yml: -------------------------------------------------------------------------------- 1 | server: webrick 2 | port: 6543 3 | #ssl_cert: test.pem 4 | #uri_path: /cas 5 | #bind_address: 0.0.0.0 6 | 7 | # database: 8 | # adapter: mysql 9 | # database: casserver 10 | # username: root 11 | # password: 12 | # host: localhost 13 | # reconnect: true 14 | database: 15 | adapter: sqlite3 16 | database: spec/casserver_spec.db 17 | 18 | disable_auto_migrations: true 19 | 20 | quiet: true 21 | 22 | authenticator: 23 | class: CASServer::Authenticators::Test 24 | password: spec_password 25 | 26 | theme: simple 27 | 28 | organization: "RSPEC-TEST" 29 | 30 | infoline: "This is an rspec test." 31 | 32 | #custom_views: /path/to/custom/views 33 | 34 | default_locale: en 35 | 36 | log: 37 | file: casserver_spec.log 38 | level: DEBUG 39 | 40 | #db_log: 41 | # file: casserver_spec_db.log 42 | 43 | enable_single_sign_out: true 44 | 45 | #maximum_unused_login_ticket_lifetime: 300 46 | #maximum_unused_service_ticket_lifetime: 300 47 | 48 | #maximum_session_lifetime: 172800 49 | 50 | #downcase_username: true 51 | -------------------------------------------------------------------------------- /spec/model_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.dirname(__FILE__) + '/spec_helper' 3 | 4 | module CASServer 5 | end 6 | require 'casserver/model' 7 | 8 | describe CASServer::Model::LoginTicket, '.cleanup(max_lifetime, max_unconsumed_lifetime)' do 9 | let(:max_lifetime) { -1 } 10 | let(:max_unconsumed_lifetime) { -2 } 11 | 12 | before do 13 | load_server(File.dirname(__FILE__) + "/default_config.yml") 14 | reset_spec_database 15 | 16 | CASServer::Model::LoginTicket.create :ticket => 'test', :client_hostname => 'test.local' 17 | end 18 | 19 | it 'should destroy all tickets created before the max lifetime' do 20 | expect { 21 | CASServer::Model::LoginTicket.cleanup(max_lifetime, max_unconsumed_lifetime) 22 | }.to change(CASServer::Model::LoginTicket, :count).by(-1) 23 | end 24 | 25 | it 'should destroy all unconsumed tickets not exceeding the max lifetime' do 26 | expect { 27 | CASServer::Model::LoginTicket.cleanup(max_lifetime, max_unconsumed_lifetime) 28 | }.to change(CASServer::Model::LoginTicket, :count).by(-1) 29 | end 30 | end 31 | 32 | describe CASServer::Model::LoginTicket, '#to_s' do 33 | let(:ticket) { 'test' } 34 | 35 | before do 36 | @login_ticket = CASServer::Model::LoginTicket.new :ticket => ticket 37 | end 38 | 39 | it 'should delegate #to_s to #ticket' do 40 | @login_ticket.to_s.should == ticket 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/spec.opts: -------------------------------------------------------------------------------- 1 | --colour 2 | --format nested 3 | --loadby mtime 4 | --reverse 5 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'sinatra' 3 | require 'rack/test' 4 | require 'rspec' 5 | #require 'spec/autorun' 6 | #require 'spec/interop/test' 7 | require 'logger' 8 | require 'ostruct' 9 | 10 | require 'capybara' 11 | require 'capybara/dsl' 12 | 13 | # set test environment 14 | set :environment, :test 15 | set :run, false 16 | set :raise_errors, true 17 | set :logging, false 18 | 19 | 20 | if Dir.getwd =~ /\/spec$/ 21 | # Avoid potential weirdness by changing the working directory to the CASServer root 22 | FileUtils.cd('..') 23 | end 24 | 25 | def silence_warnings 26 | old_verbose, $VERBOSE = $VERBOSE, nil 27 | yield 28 | ensure 29 | $VERBOSE = old_verbose 30 | end 31 | 32 | # Ugly monkeypatch to allow us to test for correct redirection to 33 | # external services. 34 | # 35 | # This will likely break in the future when Capybara or RackTest are upgraded. 36 | class Capybara::Driver::RackTest 37 | def current_url 38 | if @redirected_to_external_url 39 | @redirected_to_external_url 40 | else 41 | request.url rescue "" 42 | end 43 | end 44 | 45 | def follow_redirects! 46 | if response.redirect? && response['Location'] =~ /^http[s]?:/ 47 | @redirected_to_external_url = response['Location'] 48 | else 49 | 5.times do 50 | follow_redirect! if response.redirect? 51 | end 52 | raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if response.redirect? 53 | end 54 | end 55 | end 56 | 57 | # This called in specs' `before` block. 58 | # Due to the way Sinatra applications are loaded, 59 | # we're forced to delay loading of the server code 60 | # until the start of each test so that certain 61 | # configuraiton options can be changed (e.g. `uri_path`) 62 | def load_server(config_file) 63 | ENV['CONFIG_FILE'] = config_file 64 | 65 | silence_warnings do 66 | load File.dirname(__FILE__) + '/../lib/casserver/server.rb' 67 | end 68 | 69 | CASServer::Server.enable(:raise_errors) 70 | CASServer::Server.disable(:show_exceptions) 71 | 72 | #Capybara.current_driver = :selenium 73 | Capybara.app = CASServer::Server 74 | end 75 | 76 | # Deletes the sqlite3 database specified in the app's config 77 | # and runs the db:migrate rake tasks to rebuild the database schema. 78 | def reset_spec_database 79 | raise "Cannot reset the spec database because config[:database][:database] is not defined." unless 80 | CASServer::Server.config[:database] && CASServer::Server.config[:database][:database] 81 | 82 | FileUtils.rm_f(CASServer::Server.config[:database][:database]) 83 | 84 | ActiveRecord::Base.logger = Logger.new(STDOUT) 85 | ActiveRecord::Base.logger.level = Logger::ERROR 86 | ActiveRecord::Migration.verbose = false 87 | ActiveRecord::Migrator.migrate("db/migrate") 88 | end 89 | -------------------------------------------------------------------------------- /spec/utils_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.dirname(__FILE__) + '/spec_helper' 3 | 4 | module CASServer 5 | end 6 | require 'casserver/utils' 7 | 8 | describe CASServer::Utils, '#random_string(max_length = 29)' do 9 | before do 10 | load_server(File.dirname(__FILE__) + "/default_config.yml") 11 | reset_spec_database 12 | end 13 | 14 | context 'when max length is not passed in' do 15 | it 'should return a random string of length 29' do 16 | subject.random_string.length.should == 29 17 | end 18 | end 19 | 20 | context 'when max length is passed in' do 21 | it 'should return a random string of the desired length' do 22 | subject.random_string(30).length.should == 30 23 | end 24 | end 25 | 26 | it 'should include the letter r in the random string' do 27 | subject.random_string.should include 'r' 28 | end 29 | 30 | it 'should return a random string' do 31 | random_string = subject.random_string 32 | another_random_string = subject.random_string 33 | random_string.should_not == another_random_string 34 | end 35 | end 36 | 37 | describe CASServer::Utils, '#log_controller_action(controller, params)' do 38 | let(:params) { {} } 39 | let(:params_with_password) { { 'password' => 'test' } } 40 | let(:params_with_password_filtered) { { 'password' => '******' } } 41 | 42 | it 'should log the controller action' do 43 | $LOG.should_receive(:debug).with 'Processing application::instance_eval {}' 44 | 45 | subject.log_controller_action('application', params) 46 | end 47 | 48 | it 'should filter password parameters in the log' do 49 | $LOG.should_receive(:debug).with "Processing application::instance_eval #{params_with_password_filtered.inspect}" 50 | 51 | subject.log_controller_action('application', params_with_password) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /tasks/bundler.rake: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | namespace :bundler do 3 | Bundler::GemHelper.install_tasks(:name => 'rubycas-server') 4 | end 5 | -------------------------------------------------------------------------------- /tasks/db/migrate.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | desc "bring your CAS server database schema up to date (options CONFIG=/path/to/config.yml)" 3 | task :migrate do |t| 4 | $:.unshift File.dirname(__FILE__) + "/../../lib" 5 | 6 | require 'casserver/server' 7 | 8 | CASServer::Model::Base.logger = Logger.new(STDOUT) 9 | ActiveRecord::Migration.verbose = true 10 | ActiveRecord::Migrator.migrate("db/migrate") 11 | end 12 | end -------------------------------------------------------------------------------- /tasks/localization.rake: -------------------------------------------------------------------------------- 1 | namespace :localization do 2 | desc 'Scans the code for translatable strings and generates/updates the .po files' 3 | task :po do 4 | require 'gettext/utils' 5 | GetText.update_pofiles("rubycas-server", Dir.glob("{lib,bin}/**/*.{rb}"), "rubycas-server ") 6 | end 7 | 8 | desc 'Creates .mo files from .po files and puts them in the locale dir' 9 | task :mo do 10 | require 'gettext/utils' 11 | GetText.create_mofiles(true, "po", "locale") 12 | end 13 | end -------------------------------------------------------------------------------- /tasks/spec.rake: -------------------------------------------------------------------------------- 1 | #begin 2 | require 'rspec/core/rake_task' 3 | desc 'Run RSpecs to confirm that all functionality is working as expected' 4 | RSpec::Core::RakeTask.new('spec') do |t| 5 | t.rspec_opts = ['--colour', '--format nested'] 6 | t.pattern = 'spec/**/*_spec.rb' 7 | end 8 | #rescue LoadError 9 | # puts "Hiding spec tasks because RSpec is not available" 10 | #end 11 | --------------------------------------------------------------------------------