bringing in godfat's redesigned authenticator architecture with per-class setups... also a whole bunch of whitespace changes
This commit is contained in:
Коммит
691c58d721
|
@ -1 +1 @@
|
|||
See History.txt
|
||||
See History.txt
|
||||
|
|
62
History.txt
62
History.txt
|
@ -1,8 +1,8 @@
|
|||
=== 0.8.0 :: In Progress...
|
||||
|
||||
* NEW:
|
||||
* Support for localization via Ruby-GetText.
|
||||
See http://code.google.com/p/rubycas-server/wiki/Localization
|
||||
* Support for localization via Ruby-GetText.
|
||||
See http://code.google.com/p/rubycas-server/wiki/Localization
|
||||
for details. [antono]
|
||||
* Switched to Picnic 0.8.x, so RubyCAS-Server is now based on Rack
|
||||
and Camping 2.0 and is now compatible with Passenger Phusion
|
||||
|
@ -11,7 +11,7 @@
|
|||
* Re-licensed under the MIT License.
|
||||
|
||||
* FIXED:
|
||||
* Fixed weird problems with loading controllers when using older versions of
|
||||
* Fixed weird problems with loading controllers when using older versions of
|
||||
activesupport and/or rubygems.
|
||||
* Failure to connect to a service during a single sign out request is now
|
||||
handled gracefully.
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
=== 0.7.1 :: 2008-11-10
|
||||
|
||||
* Fixed dependency loading problems introduced by upstream changes in RubyGems
|
||||
* Fixed dependency loading problems introduced by upstream changes in RubyGems
|
||||
1.3.1.
|
||||
|
||||
=== 0.7.0 :: 2008-11-04
|
||||
|
@ -34,18 +34,18 @@
|
|||
to CAS clients alongside the username. For an example of how to do this see
|
||||
the included SQL authenticator. Also have a look at:
|
||||
http://groups.google.com/group/rubycas-server/browse_thread/thread/5eade3793cb590e9
|
||||
Note that extra attributes of type other than String or Numeric are serialized
|
||||
Note that extra attributes of type other than String or Numeric are serialized
|
||||
into YAML format before being sent along to the client.
|
||||
* Added an MD5-password version of the SQL authenticator for Drupal and any other
|
||||
database that stores its passwords in hashed form (thanks malcolmm).
|
||||
* Added new Google authenticator for authenticating against Google/GMail
|
||||
accounts.
|
||||
|
||||
|
||||
* CHANGED:
|
||||
* Service URIs are now automatically normalized. For example, if the service
|
||||
URI given to the server has a 'ticket' parameter, the ticket will now be
|
||||
automatically stripped. This is to avert any possible issues raised by
|
||||
misbehaving CAS clients (the CAS ticket should never be part of the service
|
||||
* Service URIs are now automatically normalized. For example, if the service
|
||||
URI given to the server has a 'ticket' parameter, the ticket will now be
|
||||
automatically stripped. This is to avert any possible issues raised by
|
||||
misbehaving CAS clients (the CAS ticket should never be part of the service
|
||||
URI). Same goes for other CAS-related parameters like 'service', 'renew',
|
||||
and 'gateway'. Additionally, the trailing '/' and '?' characters are
|
||||
automatically stripped from URLs, since, for example, "http://google.com/"
|
||||
|
@ -65,8 +65,8 @@
|
|||
auto-indentation has been turned off). Apparently the whitespace was
|
||||
causing problems with mod_auth_cas. See:
|
||||
http://groups.google.com/group/rubycas-server/browse_thread/thread/e482fe09999b73d3
|
||||
* When used without pre-authentication, the LDAP authenticator now tries to
|
||||
bind by searching for the given username in the LDAP directory based on the
|
||||
* When used without pre-authentication, the LDAP authenticator now tries to
|
||||
bind by searching for the given username in the LDAP directory based on the
|
||||
configured username_attribute. Prior to this change the authenticator
|
||||
attempted to bind with the LDAP server by assuming that the username credential
|
||||
matches the user's CN. This is no longer the case.
|
||||
|
@ -74,12 +74,12 @@
|
|||
are missing or incorrect) will now have HTTP status code 422. Internal server
|
||||
errors (where the server rather than the client is at fault) have error 500.
|
||||
Previously most responses had error code 200, regardless of their contents.
|
||||
|
||||
|
||||
* FIXED:
|
||||
* Fixed logout action to work properly with ActiveRecord 2.1 (eager loading behaviour
|
||||
was changed upstream forcing a change to the way we look for ProxyGrantingTickets
|
||||
to delete on logout).
|
||||
* When running under Mongrel, the USR2 signal should now restart the server as
|
||||
* When running under Mongrel, the USR2 signal should now restart the server as
|
||||
expected -- however currently this only works when the server is running
|
||||
in the foregaround. When daemonized, USR2 will shut down the server without
|
||||
restarting (see issue #58).
|
||||
|
@ -108,7 +108,7 @@
|
|||
* An encryption-enabled version of the SQL authenticator is now
|
||||
available. For more info have a look at:
|
||||
http://code.google.com/p/rubycas-server/wiki/UsingTheSQLEncryptedAuthenticator
|
||||
* Better compatibility with Oracle databases. The database migration
|
||||
* Better compatibility with Oracle databases. The database migration
|
||||
no longer tries to create tables with long names when long
|
||||
table names are not supported by the underlying database connector
|
||||
(issue #15).
|
||||
|
@ -129,7 +129,7 @@
|
|||
* Tickets generated by the server should now be a lot more secure.
|
||||
The random string generator used for generating tickets now uses
|
||||
Crypt::ISAAC. Tickets have also been extended in length; STs, PTs
|
||||
and LTs can now extend up to 32 characters, and PGTs and PGT-IOUs
|
||||
and LTs can now extend up to 32 characters, and PGTs and PGT-IOUs
|
||||
up to 64.
|
||||
|
||||
=== 0.5.0 :: 2007-09-20
|
||||
|
@ -138,8 +138,8 @@
|
|||
login page is made with gateway=true as one of the parameters, the CAS
|
||||
server will immediately redirect back to the target service along with
|
||||
a service ticket if an SSO session exists for the user (or without a
|
||||
service ticket if there is no pre-existing SSO session).
|
||||
Note that if you are using RubyCAS-Client and want gatewaying, you will
|
||||
service ticket if there is no pre-existing SSO session).
|
||||
Note that if you are using RubyCAS-Client and want gatewaying, you will
|
||||
need to upgrade it to 1.1.0 as gatewaying was broken in prior versions.
|
||||
* If gateway=true is specified as part of the logout URI, the server will
|
||||
log the user out and immediately redirect them back to the specified
|
||||
|
@ -162,9 +162,9 @@
|
|||
this new RubyCAS-Server version.
|
||||
* Multiple authenticators can now be specified. During authentication,
|
||||
credentials are presented to the first authenticator, then the second,
|
||||
and so on, until the user is validated by any one authenticator or fails
|
||||
and so on, until the user is validated by any one authenticator or fails
|
||||
validation for all of them. [jzylks]
|
||||
* When using webrick, you can now run with SSL disabled by omitting the
|
||||
* When using webrick, you can now run with SSL disabled by omitting the
|
||||
ssl_cert and ssl_key parameters.
|
||||
* Changed incorrect MySQL example database configuration -- option should
|
||||
be 'host:' not 'server:' (issue #22).
|
||||
|
@ -177,11 +177,11 @@
|
|||
LDAP server).
|
||||
* The validate() method in your authenticators now receives a :service element
|
||||
(in addition to :username, and :password). This is simply the service
|
||||
url (if any) specified in the user's CAS request. If you call
|
||||
url (if any) specified in the user's CAS request. If you call
|
||||
read_standard_credentials(credentials) at the top of your validator, the value
|
||||
will also be available as @service along with @username and @password.
|
||||
* By request, a :username_prefix option has been added to the ldap
|
||||
configuration. If entered, this string will be automatically prefixed to
|
||||
* By request, a :username_prefix option has been added to the ldap
|
||||
configuration. If entered, this string will be automatically prefixed to
|
||||
the username entered by the user.
|
||||
* A bug having to do with handling authenticator errors has been fixed.
|
||||
Any authenticator error messages should now be correctly shown on the
|
||||
|
@ -193,9 +193,9 @@
|
|||
=== 0.4.1 :: 2007-06-07
|
||||
|
||||
* This release restores compatiblity with older versions of rubygems
|
||||
(pre-0.9.0). To achieve this, we alias the 'gem' method to the old
|
||||
(pre-0.9.0). To achieve this, we alias the 'gem' method to the old
|
||||
'require_gem' if 'gem' is not already defined.
|
||||
* rubycas-server-ctl will now quiety delete an orphaned .pid file
|
||||
* rubycas-server-ctl will now quiety delete an orphaned .pid file
|
||||
instead complaining loudly and refusing to start up.
|
||||
* Fixed minor bug in rubycas-server-ctl that sometimes incorrectly reported
|
||||
startup problems when in fact the server had started just fine.
|
||||
|
@ -221,9 +221,9 @@
|
|||
In the future we may allow autocomplete to be re-enabled using a
|
||||
configuration setting.
|
||||
* When the user visits the login page and is already authenticated (i.e. they
|
||||
have a valid ticket granting cookie), a message is shown at the top
|
||||
have a valid ticket granting cookie), a message is shown at the top
|
||||
indicating that they are already logged in.
|
||||
* sqlite3-ruby is no longer required by the gem as a dependency. The user
|
||||
* sqlite3-ruby is no longer required by the gem as a dependency. The user
|
||||
must now install it manually prior to installing rubycas-server. The
|
||||
building of sqlite3 native extensions appears to be somewhat flakey
|
||||
and probably defeats the original purpose of using it (which was
|
||||
|
@ -242,9 +242,9 @@
|
|||
However, other exceptions should still be raised when errors ought
|
||||
not be recoverable (i.e. programming errors).
|
||||
* Fixed serious vulnerability in LDAP authenticator where under some
|
||||
cirumstances the user could just enter '*' as their username to match
|
||||
any username. The LDAP authenticator will now refuse to process logins
|
||||
with usernames that contain the characters * ( ) \ / and the NULL
|
||||
cirumstances the user could just enter '*' as their username to match
|
||||
any username. The LDAP authenticator will now refuse to process logins
|
||||
with usernames that contain the characters * ( ) \ / and the NULL
|
||||
character \0.
|
||||
* Views are no longer xhtml-validated. Markaby's auto-validation was turned
|
||||
off to allow for use of the autocomplete property on inputs, since this is
|
||||
|
@ -259,7 +259,7 @@
|
|||
|
||||
* ruby-casserver now behaves more like a real command-line app, accepting
|
||||
various command line arguments including -h (help), -v (version), -c (use
|
||||
an alternate config.yml), and -d (daemonize, when using webrick or mongrel
|
||||
an alternate config.yml), and -d (daemonize, when using webrick or mongrel
|
||||
mode).
|
||||
* Special characters in CAS XML responses are now properly encoded into XML
|
||||
entities
|
||||
|
|
|
@ -3,7 +3,7 @@ History.txt
|
|||
LICENSE.txt
|
||||
Manifest.txt
|
||||
PostInstall.txt
|
||||
README.txt
|
||||
README.rdoc
|
||||
Rakefile
|
||||
bin/rubycas-server
|
||||
bin/rubycas-server-ctl
|
||||
|
@ -32,6 +32,10 @@ lib/casserver/load_picnic.rb
|
|||
lib/casserver/localization.rb
|
||||
lib/casserver/models.rb
|
||||
lib/casserver/postambles.rb
|
||||
lib/casserver/template/erb/layout.html.erb
|
||||
lib/casserver/template/erb/login.html.erb
|
||||
lib/casserver/template/erb/login_form.html.erb
|
||||
lib/casserver/template/erb/logout.html.erb
|
||||
lib/casserver/utils.rb
|
||||
lib/casserver/version.rb
|
||||
lib/casserver/views.rb
|
||||
|
|
230
Rakefile
230
Rakefile
|
@ -1,115 +1,115 @@
|
|||
require 'config/requirements'
|
||||
require 'config/hoe' # setup Hoe + all gem configuration
|
||||
|
||||
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
||||
|
||||
desc "generate a self signed SSL certificate (in order to get going easily)"
|
||||
task :generate_ssl_certificate do
|
||||
`mkdir -p ssl/newcerts ssl/private`
|
||||
File.open("ssl/openssl.cnf", "w") do |f|
|
||||
f.write <<-EOF
|
||||
#
|
||||
# OpenSSL configuration file.
|
||||
#
|
||||
|
||||
# Establish working directory.
|
||||
|
||||
dir = .
|
||||
|
||||
[ ca ]
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
serial = $dir/serial
|
||||
database = $dir/index.txt
|
||||
new_certs_dir = $dir/newcerts
|
||||
certificate = $dir/cacert.pem
|
||||
private_key = $dir/private/cakey.pem
|
||||
default_days = 365
|
||||
default_md = md5
|
||||
preserve = no
|
||||
email_in_dn = no
|
||||
nameopt = default_ca
|
||||
certopt = default_ca
|
||||
policy = policy_match
|
||||
|
||||
[ policy_match ]
|
||||
countryName = match
|
||||
stateOrProvinceName = match
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ req ]
|
||||
default_bits = 1024 # Size of keys
|
||||
default_keyfile = key.pem # name of generated keys
|
||||
default_md = md5 # message digest algorithm
|
||||
string_mask = nombstr # permitted characters
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[ req_distinguished_name ]
|
||||
# Variable name Prompt string
|
||||
#---------------------- ----------------------------------
|
||||
0.organizationName = Organization Name (company)
|
||||
organizationalUnitName = Organizational Unit Name (department, division)
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 40
|
||||
localityName = Locality Name (city, district)
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
commonName = Common Name (hostname, IP, or your name)
|
||||
commonName_max = 64
|
||||
|
||||
# Default values for the above, for consistency and less typing.
|
||||
# Variable name Value
|
||||
#------------------------------ ------------------------------
|
||||
0.organizationName_default = The Sample Company
|
||||
localityName_default = Metropolis
|
||||
stateOrProvinceName_default = New York
|
||||
countryName_default = US
|
||||
commonName_default = localhost
|
||||
|
||||
[ v3_ca ]
|
||||
basicConstraints = CA:TRUE
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
||||
|
||||
[ v3_req ]
|
||||
basicConstraints = CA:FALSE
|
||||
subjectKeyIdentifier = hash
|
||||
EOF
|
||||
end
|
||||
|
||||
`cd ssl && echo '01' > serial`
|
||||
`cd ssl && touch index.txt`
|
||||
|
||||
puts
|
||||
puts "When asked for a passphrase enter one, for example rubycas"
|
||||
puts
|
||||
|
||||
`cd ssl && openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf`
|
||||
`cd ssl && openssl req -new -nodes -out req.pem -config ./openssl.cnf`
|
||||
`cd ssl && openssl ca -out cert.pem -config ./openssl.cnf -infiles req.pem`
|
||||
|
||||
|
||||
|
||||
|
||||
puts
|
||||
puts "If you are using Firefox and want to access the CAS server through localhost you need to add an exception:"
|
||||
puts " 1. Go to Preferences > Advanced > Encryption > View Certificates"
|
||||
puts " 2. Click the Tab Servers"
|
||||
puts " 3. Click the Button Add Exception"
|
||||
puts " 4. Enter https://localhost:<port> into the textfield and press Get Certificate"
|
||||
puts " 5. Then press View"
|
||||
puts " 6. Then press Confirm Security Exception"
|
||||
|
||||
end
|
||||
|
||||
desc "clear all generated files for SSL certificate"
|
||||
task :clear_ssl_certificate do
|
||||
`rm -rf ssl`
|
||||
end
|
||||
require 'config/requirements'
|
||||
require 'config/hoe' # setup Hoe + all gem configuration
|
||||
|
||||
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
||||
|
||||
desc "generate a self signed SSL certificate (in order to get going easily)"
|
||||
task :generate_ssl_certificate do
|
||||
`mkdir -p ssl/newcerts ssl/private`
|
||||
File.open("ssl/openssl.cnf", "w") do |f|
|
||||
f.write <<-EOF
|
||||
#
|
||||
# OpenSSL configuration file.
|
||||
#
|
||||
|
||||
# Establish working directory.
|
||||
|
||||
dir = .
|
||||
|
||||
[ ca ]
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
serial = $dir/serial
|
||||
database = $dir/index.txt
|
||||
new_certs_dir = $dir/newcerts
|
||||
certificate = $dir/cacert.pem
|
||||
private_key = $dir/private/cakey.pem
|
||||
default_days = 365
|
||||
default_md = md5
|
||||
preserve = no
|
||||
email_in_dn = no
|
||||
nameopt = default_ca
|
||||
certopt = default_ca
|
||||
policy = policy_match
|
||||
|
||||
[ policy_match ]
|
||||
countryName = match
|
||||
stateOrProvinceName = match
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ req ]
|
||||
default_bits = 1024 # Size of keys
|
||||
default_keyfile = key.pem # name of generated keys
|
||||
default_md = md5 # message digest algorithm
|
||||
string_mask = nombstr # permitted characters
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[ req_distinguished_name ]
|
||||
# Variable name Prompt string
|
||||
#---------------------- ----------------------------------
|
||||
0.organizationName = Organization Name (company)
|
||||
organizationalUnitName = Organizational Unit Name (department, division)
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 40
|
||||
localityName = Locality Name (city, district)
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
commonName = Common Name (hostname, IP, or your name)
|
||||
commonName_max = 64
|
||||
|
||||
# Default values for the above, for consistency and less typing.
|
||||
# Variable name Value
|
||||
#------------------------------ ------------------------------
|
||||
0.organizationName_default = The Sample Company
|
||||
localityName_default = Metropolis
|
||||
stateOrProvinceName_default = New York
|
||||
countryName_default = US
|
||||
commonName_default = localhost
|
||||
|
||||
[ v3_ca ]
|
||||
basicConstraints = CA:TRUE
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
||||
|
||||
[ v3_req ]
|
||||
basicConstraints = CA:FALSE
|
||||
subjectKeyIdentifier = hash
|
||||
EOF
|
||||
end
|
||||
|
||||
`cd ssl && echo '01' > serial`
|
||||
`cd ssl && touch index.txt`
|
||||
|
||||
puts
|
||||
puts "When asked for a passphrase enter one, for example rubycas"
|
||||
puts
|
||||
|
||||
`cd ssl && openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf`
|
||||
`cd ssl && openssl req -new -nodes -out req.pem -config ./openssl.cnf`
|
||||
`cd ssl && openssl ca -out cert.pem -config ./openssl.cnf -infiles req.pem`
|
||||
|
||||
|
||||
|
||||
|
||||
puts
|
||||
puts "If you are using Firefox and want to access the CAS server through localhost you need to add an exception:"
|
||||
puts " 1. Go to Preferences > Advanced > Encryption > View Certificates"
|
||||
puts " 2. Click the Tab Servers"
|
||||
puts " 3. Click the Button Add Exception"
|
||||
puts " 4. Enter https://localhost:<port> into the textfield and press Get Certificate"
|
||||
puts " 5. Then press View"
|
||||
puts " 6. Then press Confirm Security Exception"
|
||||
|
||||
end
|
||||
|
||||
desc "clear all generated files for SSL certificate"
|
||||
task :clear_ssl_certificate do
|
||||
`rm -rf ssl`
|
||||
end
|
||||
|
|
12
config.ru
12
config.ru
|
@ -26,13 +26,17 @@ require 'picnic'
|
|||
require 'casserver'
|
||||
|
||||
CASServer.create
|
||||
hack = lambda{ |env|
|
||||
ActiveRecord::Base.verify_active_connections!
|
||||
CASServer.call(env)
|
||||
}
|
||||
|
||||
if $CONF.uri_path
|
||||
map($CONF.uri_path) do
|
||||
map($CONF.uri_path) do
|
||||
# FIXME: this probably isn't the smartest way of remapping the themes dir to uri_path/themes
|
||||
use Rack::Static, $CONF[:static] if $CONF[:static]
|
||||
run CASServer
|
||||
end
|
||||
run hack
|
||||
end
|
||||
else
|
||||
run CASServer
|
||||
run hack
|
||||
end
|
||||
|
|
|
@ -34,6 +34,12 @@ def CASServer.create
|
|||
CASServer::Models::Base.establish_connection($CONF.database) unless CASServer::Models::Base.connected?
|
||||
CASServer::Models.create_schema
|
||||
|
||||
# setup all the authenticators
|
||||
$AUTH.zip($CONF.authenticator).each_with_index{ |auth_conf, index|
|
||||
auth, conf = auth_conf
|
||||
auth.setup(conf.merge(:auth_index => index))
|
||||
}
|
||||
|
||||
#TODO: these warnings should eventually be deleted
|
||||
if $CONF.service_ticket_expiry
|
||||
$LOG.warn "The 'service_ticket_expiry' option has been renamed to 'maximum_unused_service_ticket_lifetime'. Please make the necessary change to your config file!"
|
||||
|
|
|
@ -17,13 +17,13 @@ module Authlogic
|
|||
class AES256
|
||||
class << self
|
||||
attr_writer :key
|
||||
|
||||
|
||||
def encrypt(*tokens)
|
||||
aes.encrypt
|
||||
aes.key = @key
|
||||
[aes.update(tokens.join) + aes.final].pack("m").chomp
|
||||
end
|
||||
|
||||
|
||||
def matches?(crypted, *tokens)
|
||||
aes.decrypt
|
||||
aes.key = @key
|
||||
|
@ -31,7 +31,7 @@ module Authlogic
|
|||
rescue OpenSSL::CipherError
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def aes
|
||||
raise ArgumentError.new("You must provide a key like #{name}.key = my_key before using the #{name}") if @key.blank?
|
||||
|
@ -40,4 +40,4 @@ module Authlogic
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,12 +48,12 @@ module Authlogic
|
|||
@cost ||= 10
|
||||
end
|
||||
attr_writer :cost
|
||||
|
||||
|
||||
# Creates a BCrypt hash for the password passed.
|
||||
def encrypt(*tokens)
|
||||
::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
|
||||
end
|
||||
|
||||
|
||||
# Does the hash match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(hash, *tokens)
|
||||
$LOG.debug hash
|
||||
|
@ -63,7 +63,7 @@ module Authlogic
|
|||
return false if hash.blank?
|
||||
hash == join_tokens(tokens)
|
||||
end
|
||||
|
||||
|
||||
# This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost
|
||||
def cost_matches?(hash)
|
||||
hash = new_from_hash(hash)
|
||||
|
@ -73,12 +73,12 @@ module Authlogic
|
|||
hash.cost == cost
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def join_tokens(tokens)
|
||||
tokens.flatten.join
|
||||
end
|
||||
|
||||
|
||||
def new_from_hash(hash)
|
||||
begin
|
||||
::BCrypt::Password.new(hash)
|
||||
|
@ -89,4 +89,4 @@ module Authlogic
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
require "digest/md5"
|
||||
|
||||
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
# This class was made for the users transitioning from md5 based systems.
|
||||
# I highly discourage using this crypto provider as it superbly inferior
|
||||
# This class was made for the users transitioning from md5 based systems.
|
||||
# I highly discourage using this crypto provider as it superbly inferior
|
||||
# to your other options.
|
||||
#
|
||||
# Please use any other provider offered by Authlogic.
|
||||
class MD5
|
||||
class << self
|
||||
attr_accessor :join_token
|
||||
|
||||
|
||||
# The number of times to loop through the encryption.
|
||||
def stretches
|
||||
@stretches ||= 1
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
|
||||
# Turns your raw password into a MD5 hash.
|
||||
def encrypt(*tokens)
|
||||
digest = tokens.flatten.join(join_token)
|
||||
stretches.times { digest = Digest::MD5.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
|
@ -31,4 +31,4 @@ module Authlogic
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,13 +10,13 @@ module Authlogic
|
|||
@join_token ||= "--"
|
||||
end
|
||||
attr_writer :join_token
|
||||
|
||||
|
||||
# The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
|
||||
def stretches
|
||||
@stretches ||= 10
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
|
||||
# Turns your raw password into a Sha1 hash.
|
||||
def encrypt(*tokens)
|
||||
tokens = tokens.flatten
|
||||
|
@ -24,7 +24,7 @@ module Authlogic
|
|||
stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token)) }
|
||||
digest
|
||||
end
|
||||
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
|
@ -32,4 +32,4 @@ module Authlogic
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,20 +26,20 @@ module Authlogic
|
|||
class Sha512
|
||||
class << self
|
||||
attr_accessor :join_token
|
||||
|
||||
|
||||
# The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
|
||||
def stretches
|
||||
@stretches ||= 20
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
|
||||
# Turns your raw password into a Sha512 hash.
|
||||
def encrypt(*tokens)
|
||||
digest = tokens.flatten.join(join_token)
|
||||
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
|
@ -47,4 +47,4 @@ module Authlogic
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,24 +1,31 @@
|
|||
module CASServer
|
||||
module Authenticators
|
||||
class Base
|
||||
def self.setup opts
|
||||
# this would be called at rubycas-server start-up,
|
||||
# override this method to setup what you need,
|
||||
# e.g. setup database connection.
|
||||
# leave it empty if you don't need to setup something.
|
||||
end
|
||||
|
||||
attr_accessor :options
|
||||
attr_reader :username # make this accessible so that we can pick up any
|
||||
attr_reader :username # make this accessible so that we can pick up any
|
||||
# transformations done within the authenticator
|
||||
|
||||
|
||||
def validate(credentials)
|
||||
raise NotImplementedError, "This method must be implemented by a class extending #{self.class}"
|
||||
end
|
||||
|
||||
|
||||
def configure(options)
|
||||
raise ArgumentError, "options must be a HashWithIndifferentAccess" unless options.kind_of? HashWithIndifferentAccess
|
||||
@options = options.dup
|
||||
@extra_attributes = {}
|
||||
end
|
||||
|
||||
|
||||
def extra_attributes
|
||||
@extra_attributes
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def read_standard_credentials(credentials)
|
||||
@username = credentials[:username]
|
||||
|
@ -26,7 +33,7 @@ module CASServer
|
|||
@service = credentials[:service]
|
||||
@request = credentials[:request]
|
||||
end
|
||||
|
||||
|
||||
def extra_attributes_to_extract
|
||||
if @options[:extra_attributes].kind_of? Array
|
||||
attrs = @options[:extra_attributes]
|
||||
|
@ -36,13 +43,13 @@ module CASServer
|
|||
$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.")
|
||||
attrs = []
|
||||
end
|
||||
|
||||
|
||||
$LOG.debug("#{self.class.name} will try to extract the following extra_attributes: #{attrs.inspect}")
|
||||
return attrs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class AuthenticatorError < Exception
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ require 'casserver/authenticators/base'
|
|||
# fall back to some other authentication mechanism.
|
||||
#
|
||||
# Here's an example of how to use two chained authenticators in the config.yml
|
||||
# file. The server will first use the ClientCertificate authenticator, and
|
||||
# file. The server will first use the ClientCertificate authenticator, and
|
||||
# only fall back to the SQL authenticator of the first one fails:
|
||||
#
|
||||
# authenticator:
|
||||
|
@ -30,17 +30,17 @@ require 'casserver/authenticators/base'
|
|||
class CASServer::Authenticators::ClientCertificate < CASServer::Authenticators::Base
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
|
||||
@client_cert = credentials[:request]['SSL_CLIENT_CERT']
|
||||
|
||||
|
||||
# note that I haven't actually tested to see if SSL_CLIENT_CERT gets
|
||||
# filled with data when a client cert is provided, but this should be
|
||||
# the case at least in theory :)
|
||||
|
||||
|
||||
return false if @client_cert.blank?
|
||||
|
||||
|
||||
# IMPLEMENT SSL CERTIFICATE VALIDATION CODE HERE
|
||||
|
||||
|
||||
return true # if SSL certificate is valid, false otherwise
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'net/http'
|
|||
require 'net/https'
|
||||
require 'timeout'
|
||||
|
||||
# Validates Google accounts against Google's authentication service -- in other
|
||||
# Validates Google accounts against Google's authentication service -- in other
|
||||
# words, this authenticator allows users to log in to CAS using their
|
||||
# Gmail/Google accounts.
|
||||
class CASServer::Authenticators::Google < CASServer::Authenticators::Base
|
||||
|
@ -12,19 +12,19 @@ class CASServer::Authenticators::Google < CASServer::Authenticators::Base
|
|||
read_standard_credentials(credentials)
|
||||
|
||||
return false if @username.blank? || @password.blank?
|
||||
|
||||
|
||||
auth_data = {
|
||||
'Email' => @username,
|
||||
'Passwd' => @password,
|
||||
'service' => 'xapi',
|
||||
'Email' => @username,
|
||||
'Passwd' => @password,
|
||||
'service' => 'xapi',
|
||||
'source' => 'RubyCAS-Server',
|
||||
'accountType' => 'HOSTED_OR_GOOGLE'
|
||||
}
|
||||
|
||||
|
||||
url = URI.parse('https://www.google.com/accounts/ClientLogin')
|
||||
http = Net::HTTP.new(url.host, url.port)
|
||||
http.use_ssl = true
|
||||
|
||||
|
||||
# TODO: make the timeout configurable
|
||||
wait_seconds = 10
|
||||
begin
|
||||
|
@ -34,7 +34,7 @@ class CASServer::Authenticators::Google < CASServer::Authenticators::Base
|
|||
req.set_form_data(auth_data,'&')
|
||||
conn.request(req)
|
||||
end
|
||||
|
||||
|
||||
case res
|
||||
when Net::HTTPSuccess
|
||||
true
|
||||
|
|
|
@ -26,47 +26,47 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|||
read_standard_credentials(credentials)
|
||||
|
||||
return false if @password.blank?
|
||||
|
||||
|
||||
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
||||
raise CASServer::AuthenticatorError, "Invalid LDAP authenticator configuration!" unless @options[:ldap]
|
||||
raise CASServer::AuthenticatorError, "You must specify a server host in the LDAP configuration!" unless @options[:ldap][:host] || @options[:ldap][:server]
|
||||
|
||||
|
||||
raise CASServer::AuthenticatorError, "The username '#{@username}' contains invalid characters." if (@username =~ /[*\(\)\0\/]/)
|
||||
|
||||
|
||||
preprocess_username
|
||||
|
||||
|
||||
@ldap = Net::LDAP.new
|
||||
|
||||
|
||||
|
||||
|
||||
@options[:ldap][:host] ||= @options[:ldap][:server]
|
||||
@ldap.host = @options[:ldap][:host]
|
||||
@ldap.port = @options[:ldap][:port] if @options[:ldap][:port]
|
||||
@ldap.encryption(@options[:ldap][:encryption].intern) if @options[:ldap][:encryption]
|
||||
|
||||
|
||||
begin
|
||||
if @options[:ldap][:auth_user]
|
||||
bind_success = bind_by_username_with_preauthentication
|
||||
else
|
||||
bind_success = bind_by_username
|
||||
end
|
||||
|
||||
|
||||
return false unless bind_success
|
||||
|
||||
|
||||
entry = find_user
|
||||
extract_extra_attributes(entry)
|
||||
|
||||
|
||||
return true
|
||||
rescue Net::LDAP::LdapError => e
|
||||
raise CASServer::AuthenticatorError,
|
||||
"LDAP authentication failed with '#{e}'. Check your authenticator configuration."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def default_username_attribute
|
||||
"cn"
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
# Add prefix to username, if :username_prefix was specified in the :ldap config.
|
||||
def preprocess_username
|
||||
|
@ -78,34 +78,34 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|||
# added to the LDAP query for the username.
|
||||
def bind_by_username
|
||||
username_attribute = options[:ldap][:username_attribute] || default_username_attribute
|
||||
|
||||
|
||||
@ldap.bind_as(:base => @options[:ldap][:base], :password => @password, :filter => user_filter)
|
||||
end
|
||||
|
||||
# If an auth_user is specified, we will connect ("pre-authenticate") with the
|
||||
# LDAP server using the authenticator account, and then attempt to bind as the
|
||||
# user who is actually trying to authenticate. Note that you need to set up
|
||||
# user who is actually trying to authenticate. Note that you need to set up
|
||||
# the special authenticator account first. Also, auth_user must be the authenticator
|
||||
# user's full CN, which is probably not the same as their username.
|
||||
#
|
||||
# This pre-authentication process is necessary because binding can only be done
|
||||
# using the CN, so having just the username is not enough. We connect as auth_user,
|
||||
# using the CN, so having just the username is not enough. We connect as auth_user,
|
||||
# and then try to find the target user's CN based on the given username. Then we bind
|
||||
# as the target user to validate their credentials.
|
||||
def bind_by_username_with_preauthentication
|
||||
raise CASServer::AuthenticatorError, "A password must be specified in the configuration for the authenticator user!" unless
|
||||
raise CASServer::AuthenticatorError, "A password must be specified in the configuration for the authenticator user!" unless
|
||||
@options[:ldap][:auth_password]
|
||||
|
||||
|
||||
@ldap.authenticate(@options[:ldap][:auth_user], @options[:ldap][:auth_password])
|
||||
|
||||
|
||||
@ldap.bind_as(:base => @options[:ldap][:base], :password => @password, :filter => user_filter)
|
||||
end
|
||||
|
||||
|
||||
# Combine the filter for finding the user with the optional extra filter specified in the config
|
||||
# (if any).
|
||||
def user_filter
|
||||
username_attribute = options[:ldap][:username_attribute] || default_username_attribute
|
||||
|
||||
|
||||
filter = Net::LDAP::Filter.eq(username_attribute, @username)
|
||||
unless @options[:ldap][:filter].blank?
|
||||
filter &= Net::LDAP::Filter.construct(@options[:ldap][:filter])
|
||||
|
@ -113,14 +113,14 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|||
|
||||
filter
|
||||
end
|
||||
|
||||
|
||||
# Finds the user based on the user_filter (this is called after authentication).
|
||||
# We do this to make it possible to extract extra_attributes.
|
||||
def find_user
|
||||
results = @ldap.search( :base => options[:ldap][:base], :filter => user_filter)
|
||||
return results.first
|
||||
end
|
||||
|
||||
|
||||
def extract_extra_attributes(ldap_entry)
|
||||
@extra_attributes = {}
|
||||
extra_attributes_to_extract.each do |attr|
|
||||
|
@ -136,7 +136,7 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if @extra_attributes.empty?
|
||||
$LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
|
||||
else
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# I started working on this but run into a wall, so I am commiting what I've got
|
||||
# done and leaving it here with hopes of one day finishing it.
|
||||
#
|
||||
#
|
||||
# The main problem is that although I've got the Lan Manager/NTLM password hash,
|
||||
# I'm not sure what to do with it. i.e. I need to check it against the AD or SMB
|
||||
# server or something... maybe faking an SMB share connection and using the LM
|
||||
|
@ -35,10 +35,10 @@ module CASServer
|
|||
else
|
||||
raise "Invalid NTLM reply from client."
|
||||
end
|
||||
|
||||
|
||||
if t1
|
||||
$LOG.debug "T1: #{t1.inspect}"
|
||||
|
||||
|
||||
# now put together a Type2 message asking for the client to send
|
||||
# back NTLM credentials (LM hash and such)
|
||||
t2 = Net::NTLM::Message::Type2.new
|
||||
|
@ -46,11 +46,11 @@ module CASServer
|
|||
t2.set_flag :NTLM
|
||||
t2.context = 0x0000000000000000 # this can probably just be left unassigned
|
||||
t2.challenge = 0x0123456789abcdef # this should be a random 8-byte integer
|
||||
|
||||
|
||||
$LOG.debug "T2: #{t2.inspect}"
|
||||
$LOG.debug "T2: #{t2.serialize}"
|
||||
headers["WWW-Authenticate"] = "NTLM #{t2.encode64}"
|
||||
|
||||
|
||||
# the client should respond to this with a Type3 message...
|
||||
r('401', '', headers)
|
||||
return
|
||||
|
@ -58,7 +58,7 @@ module CASServer
|
|||
# NOTE: for some reason the server never receives the T3 response, even though monitoring
|
||||
# the HTTP traffic I can see that the client does send it back... there's probably
|
||||
# another bug hiding somewhere here
|
||||
|
||||
|
||||
lm_response = t3.lm_response
|
||||
ntlm_response = t3.ntlm_response
|
||||
username = t3.user
|
||||
|
@ -67,8 +67,8 @@ module CASServer
|
|||
# call would do it?
|
||||
$LOG.debug "T3 LM: #{lm_response.inspect}"
|
||||
$LOG.debug "T3 NTLM: #{ntlm_response.inspect}"
|
||||
|
||||
# assuming the authentication was successful, we'll now need to do something in the
|
||||
|
||||
# assuming the authentication was successful, we'll now need to do something in the
|
||||
# controller acting as if we'd received correct login credentials (i.e. proceed as if
|
||||
# CAS authentication was successful).... if authentication failed, then we should
|
||||
# just fall back to old-school web-based authentication, asking the user to enter
|
||||
|
@ -85,4 +85,4 @@ module CASServer
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,10 +13,10 @@ class CASServer::Authenticators::OpenID < CASServer::Authenticators::Base
|
|||
def validate(credentials)
|
||||
raise NotImplementedError, "The OpenID authenticator is not yet implemented. "+
|
||||
"See http://code.google.com/p/rubycas-server/issues/detail?id=36 if you are interested in helping this along."
|
||||
|
||||
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
|
||||
store = OpenID::Store::Memory.new
|
||||
consumer = OpenID::Consumer.new({}, store)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,15 +7,15 @@ rescue LoadError
|
|||
require 'active_record'
|
||||
end
|
||||
|
||||
# Authenticates against a plain SQL table.
|
||||
#
|
||||
# This assumes that all of your users are stored in a table that has a 'username'
|
||||
# column and a 'password' column. When the user logs in, CAS conects to the
|
||||
# database and looks for a matching username/password in the users table. If a
|
||||
# Authenticates against a plain SQL table.
|
||||
#
|
||||
# This assumes that all of your users are stored in a table that has a 'username'
|
||||
# column and a 'password' column. When the user logs in, CAS conects to the
|
||||
# database and looks for a matching username/password in the users table. If a
|
||||
# matching username and password is found, authentication is successful.
|
||||
#
|
||||
# Any database backend supported by ActiveRecord can be used.
|
||||
#
|
||||
#
|
||||
# Config example:
|
||||
#
|
||||
# authenticator:
|
||||
|
@ -24,7 +24,7 @@ end
|
|||
# adapter: mysql
|
||||
# database: some_database_with_users_table
|
||||
# username: root
|
||||
# password:
|
||||
# password:
|
||||
# server: localhost
|
||||
# user_table: users
|
||||
# username_column: username
|
||||
|
@ -34,10 +34,10 @@ end
|
|||
# provide the client with the authenticated user's username. However it is now
|
||||
# possible for the server to provide the client with additional attributes.
|
||||
# You can configure the SQL authenticator to provide data from additional
|
||||
# columns in the users table by listing the names of the columns under the
|
||||
# columns in the users table by listing the names of the columns under the
|
||||
# 'extra_attributes' option. Note though that this functionality is experimental.
|
||||
# It should work with RubyCAS-Client, but may or may not work with other CAS
|
||||
# clients.
|
||||
# clients.
|
||||
#
|
||||
# For example, with this configuration, the 'full_name' and 'access_level'
|
||||
# columns will be provided to your CAS clients along with the username:
|
||||
|
@ -51,43 +51,53 @@ end
|
|||
# username_column: username
|
||||
# password_column: password
|
||||
# extra_attributes: full_name, access_level
|
||||
#
|
||||
#
|
||||
class CASServer::Authenticators::SQL < CASServer::Authenticators::Base
|
||||
def self.setup opts
|
||||
raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless opts[:database]
|
||||
|
||||
user_model_name = "CASUser_#{opts[:auth_index]}"
|
||||
$LOG.debug "CREATING USER MODEL #{user_model_name}"
|
||||
|
||||
class_eval %{
|
||||
class #{user_model_name} < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
|
||||
@user_model = const_get(user_model_name)
|
||||
@user_model.establish_connection(opts[:database])
|
||||
@user_model.set_table_name(opts[:user_table] || 'users')
|
||||
end
|
||||
|
||||
def self.user_model
|
||||
@user_model
|
||||
end
|
||||
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
||||
|
||||
user_model = establish_database_connection_if_necessary
|
||||
|
||||
raise_if_not_configured
|
||||
|
||||
user_model = self.class.user_model
|
||||
|
||||
username_column = @options[:username_column] || 'username'
|
||||
password_column = @options[:password_column] || 'password'
|
||||
|
||||
|
||||
results = user_model.find(:all, :conditions => ["#{username_column} = ? AND #{password_column} = ?", @username, @password])
|
||||
|
||||
|
||||
if results.size > 0
|
||||
$LOG.warn("#{self.class}: Multiple matches found for user #{@username.inspect}") if results.size > 1
|
||||
|
||||
|
||||
unless @options[:extra_attributes].blank?
|
||||
if results.size > 1
|
||||
$LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}")
|
||||
else
|
||||
user = results.first
|
||||
|
||||
@extra_attributes = {}
|
||||
extra_attributes_to_extract.each do |col|
|
||||
@extra_attributes[col] = user.send(col)
|
||||
end
|
||||
|
||||
if @extra_attributes.empty?
|
||||
$LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
|
||||
else
|
||||
$LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}")
|
||||
end
|
||||
|
||||
extract_extra(user)
|
||||
log_extra
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
@ -95,25 +105,24 @@ class CASServer::Authenticators::SQL < CASServer::Authenticators::Base
|
|||
end
|
||||
|
||||
protected
|
||||
def establish_database_connection_if_necessary
|
||||
raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless @options[:database]
|
||||
|
||||
user_model_name = "CASUser_#{@options[:auth_index]}"
|
||||
if self.class.const_defined?(user_model_name)
|
||||
$LOG.debug "REUSING USER MODEL #{user_model_name}"
|
||||
user_model = self.class.const_get(user_model_name)
|
||||
else
|
||||
$LOG.debug "CREATING USER MODEL #{user_model_name}"
|
||||
self.class.class_eval %{
|
||||
class #{user_model_name} < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
user_model = self.class.const_get(user_model_name)
|
||||
user_model.establish_connection(options[:database])
|
||||
user_model.set_table_name @options[:user_table] || "users"
|
||||
end
|
||||
|
||||
user_model
|
||||
def raise_if_not_configured
|
||||
raise CASServer::AuthenticatorError.new(
|
||||
"Cannot validate credentials because the authenticator hasn't yet been configured"
|
||||
) unless @options
|
||||
end
|
||||
|
||||
end
|
||||
def extract_extra user
|
||||
@extra_attributes = {}
|
||||
extra_attributes_to_extract.each do |col|
|
||||
@extra_attributes[col] = user.send(col)
|
||||
end
|
||||
end
|
||||
|
||||
def log_extra
|
||||
if @extra_attributes.empty?
|
||||
$LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
|
||||
else
|
||||
$LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,15 +15,15 @@ rescue LoadError
|
|||
require 'active_record'
|
||||
end
|
||||
|
||||
# This is a version of the SQL authenticator that works nicely with Authlogic.
|
||||
# Passwords are encrypted the same way as it done in Authlogic.
|
||||
# Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
|
||||
# config.
|
||||
# This is a version of the SQL authenticator that works nicely with Authlogic.
|
||||
# Passwords are encrypted the same way as it done in Authlogic.
|
||||
# Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
|
||||
# config.
|
||||
#
|
||||
# Using this authenticator requires restful authentication plugin on rails (client) side.
|
||||
#
|
||||
# * git://github.com/binarylogic/authlogic.git
|
||||
#
|
||||
#
|
||||
# Usage:
|
||||
|
||||
# authenticator:
|
||||
|
@ -44,11 +44,10 @@ class CASServer::Authenticators::SQLAuthlogic < CASServer::Authenticators::SQL
|
|||
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
||||
|
||||
user_model = establish_database_connection_if_necessary
|
||||
|
||||
raise_if_not_configured
|
||||
|
||||
user_model = self.class.user_model
|
||||
|
||||
username_column = @options[:username_column] || "login"
|
||||
password_column = @options[:password_column] || "crypted_password"
|
||||
salt_column = @options[:salt_column]
|
||||
|
@ -70,17 +69,10 @@ class CASServer::Authenticators::SQLAuthlogic < CASServer::Authenticators::SQL
|
|||
if results.size > 1
|
||||
$LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}")
|
||||
else
|
||||
|
||||
@extra_attributes = {}
|
||||
extra_attributes_to_extract.each do |col|
|
||||
@extra_attributes[col] = user.send(col)
|
||||
end
|
||||
|
||||
if @extra_attributes.empty?
|
||||
$LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
|
||||
else
|
||||
$LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}")
|
||||
end
|
||||
|
||||
extract_extra(user)
|
||||
log_extra
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'casserver/authenticators/base'
|
||||
require 'casserver/authenticators/sql'
|
||||
|
||||
require 'digest/sha1'
|
||||
require 'digest/sha2'
|
||||
|
@ -6,58 +6,15 @@ require 'digest/sha2'
|
|||
$: << File.dirname(File.expand_path(__FILE__)) + "/../../../vendor/isaac_0.9.1"
|
||||
require 'crypt/ISAAC'
|
||||
|
||||
begin
|
||||
require 'active_record'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'active_record'
|
||||
end
|
||||
|
||||
# This is a more secure version of the SQL authenticator. Passwords are encrypted
|
||||
# This is a more secure version of the SQL authenticator. Passwords are encrypted
|
||||
# rather than being stored in plain text.
|
||||
#
|
||||
# Based on code contributed by Ben Mabey.
|
||||
#
|
||||
# Using this authenticator requires some configuration on the client side. Please see
|
||||
# http://code.google.com/p/rubycas-server/wiki/UsingTheSQLEncryptedAuthenticator
|
||||
class CASServer::Authenticators::SQLEncrypted < CASServer::Authenticators::Base
|
||||
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
||||
|
||||
user_model = establish_database_connection_if_necessary
|
||||
|
||||
username_column = @options[:username_column] || "username"
|
||||
encrypt_function = @options[:encrypt_function] || 'user.encrypted_password == Digest::SHA256.hexdigest("#{user.encryption_salt}::#{@password}")'
|
||||
|
||||
results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username])
|
||||
|
||||
if results.size > 0
|
||||
$LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
|
||||
user = results.first
|
||||
|
||||
unless @options[:extra_attributes].blank?
|
||||
@extra_attributes = {}
|
||||
extra_attributes_to_extract.each do |col|
|
||||
@extra_attributes[col] = user.send(col)
|
||||
end
|
||||
|
||||
if @extra_attributes.empty?
|
||||
$LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
|
||||
else
|
||||
$LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
return eval(encrypt_function)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# Include this module into your application's user model.
|
||||
class CASServer::Authenticators::SQLEncrypted < CASServer::Authenticators::SQL
|
||||
# Include this module into your application's user model.
|
||||
#
|
||||
# Your model must have an 'encrypted_password' column where the password will be stored,
|
||||
# and an 'encryption_salt' column that will be populated with a random string before
|
||||
|
@ -67,40 +24,44 @@ class CASServer::Authenticators::SQLEncrypted < CASServer::Authenticators::Base
|
|||
raise "#{self} should be inclued in an ActiveRecord class!" unless mod.respond_to?(:before_save)
|
||||
mod.before_save :generate_encryption_salt
|
||||
end
|
||||
|
||||
|
||||
def encrypt(str)
|
||||
generate_encryption_salt unless encryption_salt
|
||||
Digest::SHA256.hexdigest("#{encryption_salt}::#{str}")
|
||||
end
|
||||
|
||||
|
||||
def password=(password)
|
||||
self[:encrypted_password] = encrypt(password)
|
||||
end
|
||||
|
||||
|
||||
def generate_encryption_salt
|
||||
self.encryption_salt = Digest::SHA1.hexdigest(Crypt::ISAAC.new.rand(2**31).to_s) unless
|
||||
encryption_salt
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def establish_database_connection_if_necessary
|
||||
raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless @options[:database]
|
||||
def self.setup opts
|
||||
super(opts)
|
||||
user_model.__send__(:include, EncryptedPassword)
|
||||
end
|
||||
|
||||
user_model_name = "CASUser_#{@options[:auth_index]}"
|
||||
if self.class.const_defined?(user_model_name)
|
||||
user_model = self.class.const_get(user_model_name)
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
raise_if_not_configured
|
||||
|
||||
user_model = self.class.user_model
|
||||
|
||||
username_column = @options[:username_column] || "username"
|
||||
encrypt_function = @options[:encrypt_function] || 'user.encrypted_password == Digest::SHA256.hexdigest("#{user.encryption_salt}::#{@password}")'
|
||||
|
||||
results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username])
|
||||
|
||||
if results.size > 0
|
||||
$LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
|
||||
user = results.first
|
||||
return eval(encrypt_function)
|
||||
else
|
||||
self.class.class_eval %{
|
||||
class #{user_model_name} < ActiveRecord::Base
|
||||
include EncryptedPassword
|
||||
end
|
||||
}
|
||||
user_model = self.class.const_get(user_model_name)
|
||||
user_model.set_table_name @options[:user_table] || "users"
|
||||
user_model.establish_connection(options[:database])
|
||||
return false
|
||||
end
|
||||
|
||||
user_model
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,11 +9,11 @@ require 'digest/md5'
|
|||
# Drupal, you should use 'name' for the :username_column config option, and
|
||||
# 'pass' for the :password_column.
|
||||
class CASServer::Authenticators::SQLMd5 < CASServer::Authenticators::SQL
|
||||
|
||||
|
||||
protected
|
||||
def read_standard_credentials(credentials)
|
||||
super
|
||||
@password = Digest::MD5.hexdigest(@password)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,10 +9,10 @@ rescue LoadError
|
|||
require 'active_record'
|
||||
end
|
||||
|
||||
# This is a version of the SQL authenticator that works nicely with RestfulAuthentication.
|
||||
# Passwords are encrypted the same way as it done in RestfulAuthentication.
|
||||
# Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
|
||||
# config.
|
||||
# This is a version of the SQL authenticator that works nicely with RestfulAuthentication.
|
||||
# Passwords are encrypted the same way as it done in RestfulAuthentication.
|
||||
# Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
|
||||
# config.
|
||||
#
|
||||
# Using this authenticator requires restful authentication plugin on rails (client) side.
|
||||
#
|
||||
|
@ -22,27 +22,26 @@ class CASServer::Authenticators::SQLRestAuth < CASServer::Authenticators::SQLEnc
|
|||
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
||||
raise_if_not_configured
|
||||
|
||||
user_model = self.class.user_model
|
||||
|
||||
user_model = establish_database_connection_if_necessary
|
||||
|
||||
username_column = @options[:username_column] || "email"
|
||||
|
||||
|
||||
results = user_model.find(:all, :conditions => ["#{username_column} = ?", @username])
|
||||
|
||||
|
||||
if results.size > 0
|
||||
$LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
|
||||
user = results.first
|
||||
return (user.crypted_password == user.encrypt(@password))
|
||||
return (user.crypted_password == user.encrypt(@password))
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module EncryptedPassword
|
||||
|
||||
# XXX: this constants MUST be defined in config.
|
||||
# XXX: this constants MUST be defined in config.
|
||||
# For more details # look at restful-authentication docs.
|
||||
#
|
||||
REST_AUTH_DIGEST_STRETCHES = $CONF.rest_auth_digest_streches
|
||||
|
@ -51,11 +50,11 @@ class CASServer::Authenticators::SQLRestAuth < CASServer::Authenticators::SQLEnc
|
|||
def self.included(mod)
|
||||
raise "#{self} should be inclued in an ActiveRecord class!" unless mod.respond_to?(:before_save)
|
||||
end
|
||||
|
||||
|
||||
def encrypt(password)
|
||||
password_digest(password, self.salt)
|
||||
end
|
||||
|
||||
|
||||
def secure_digest(*args)
|
||||
Digest::SHA1.hexdigest(args.flatten.join('--'))
|
||||
end
|
||||
|
@ -66,6 +65,6 @@ class CASServer::Authenticators::SQLRestAuth < CASServer::Authenticators::SQLEnc
|
|||
digest = secure_digest(digest, salt, password, REST_AUTH_SITE_KEY)
|
||||
end
|
||||
digest
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
require 'casserver/authenticators/base'
|
||||
|
||||
# Dummy authenticator used for testing.
|
||||
# Dummy authenticator used for testing.
|
||||
# Accepts any username as valid as long as the password is "testpassword"; otherwise authentication fails.
|
||||
# Raises an AuthenticationError when username is "do_error" (this is useful to test the Exception
|
||||
# handling functionality).
|
||||
class CASServer::Authenticators::Test < CASServer::Authenticators::Base
|
||||
def validate(credentials)
|
||||
read_standard_credentials(credentials)
|
||||
|
||||
|
||||
raise CASServer::AuthenticatorError, "Username is 'do_error'!" if @username == 'do_error'
|
||||
|
||||
|
||||
@extra_attributes[:test_string] = "testing!"
|
||||
@extra_attributes[:test_numeric] = 123.45
|
||||
@extra_attributes[:test_serialized] = {:foo => 'bar', :alpha => [1,2,3]}
|
||||
|
||||
|
||||
return @password == "testpassword"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,19 +11,19 @@ module CASServer::CAS
|
|||
# 3.5 (login ticket)
|
||||
lt = LoginTicket.new
|
||||
lt.ticket = "LT-" + CASServer::Utils.random_string
|
||||
|
||||
|
||||
lt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
||||
lt.save!
|
||||
$LOG.debug("Generated login ticket '#{lt.ticket}' for client" +
|
||||
" at '#{lt.client_hostname}'")
|
||||
lt
|
||||
end
|
||||
|
||||
|
||||
# Creates a TicketGrantingTicket for the given username. This is done when the user logs in
|
||||
# for the first time to establish their SSO session (after their credentials have been validated).
|
||||
#
|
||||
# The optional 'extra_attributes' parameter takes a hash of additional attributes
|
||||
# that will be sent along with the username in the CAS response to subsequent
|
||||
# that will be sent along with the username in the CAS response to subsequent
|
||||
# validation requests from clients.
|
||||
def generate_ticket_granting_ticket(username, extra_attributes = {})
|
||||
# 3.6 (ticket granting cookie/ticket)
|
||||
|
@ -34,11 +34,11 @@ module CASServer::CAS
|
|||
tgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
||||
tgt.save!
|
||||
$LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" +
|
||||
" '#{tgt.username}' at '#{tgt.client_hostname}'" +
|
||||
" '#{tgt.username}' at '#{tgt.client_hostname}'" +
|
||||
(extra_attributes.blank? ? "" : " with extra attributes #{extra_attributes.inspect}"))
|
||||
tgt
|
||||
end
|
||||
|
||||
|
||||
def generate_service_ticket(service, username, tgt)
|
||||
# 3.1 (service ticket)
|
||||
st = ServiceTicket.new
|
||||
|
@ -52,7 +52,7 @@ module CASServer::CAS
|
|||
" for user '#{st.username}' at '#{st.client_hostname}'")
|
||||
st
|
||||
end
|
||||
|
||||
|
||||
def generate_proxy_ticket(target_service, pgt)
|
||||
# 3.2 (proxy ticket)
|
||||
pt = ProxyTicket.new
|
||||
|
@ -68,19 +68,19 @@ module CASServer::CAS
|
|||
" ticket '#{pgt.ticket}'")
|
||||
pt
|
||||
end
|
||||
|
||||
|
||||
def generate_proxy_granting_ticket(pgt_url, st)
|
||||
uri = URI.parse(pgt_url)
|
||||
https = Net::HTTP.new(uri.host,uri.port)
|
||||
https.use_ssl = true
|
||||
|
||||
|
||||
# Here's what's going on here:
|
||||
#
|
||||
#
|
||||
# 1. We generate a ProxyGrantingTicket (but don't store it in the database just yet)
|
||||
# 2. Deposit the PGT and it's associated IOU at the proxy callback URL.
|
||||
# 3. If the proxy callback URL responds with HTTP code 200, store the PGT and return it;
|
||||
# otherwise don't save it and return nothing.
|
||||
#
|
||||
#
|
||||
https.start do |conn|
|
||||
path = uri.path.empty? ? '/' : uri.path
|
||||
path += '?' + uri.query unless (uri.query.nil? || uri.query.empty?)
|
||||
|
@ -90,12 +90,12 @@ module CASServer::CAS
|
|||
pgt.iou = "PGTIOU-" + CASServer::Utils.random_string(57)
|
||||
pgt.service_ticket_id = st.id
|
||||
pgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
||||
|
||||
|
||||
# FIXME: The CAS protocol spec says to use 'pgt' as the parameter, but in practice
|
||||
# the JA-SIG and Yale server implementations use pgtId. We'll go with the
|
||||
# in-practice standard.
|
||||
path += (uri.query.nil? || uri.query.empty? ? '?' : '&') + "pgtId=#{pgt.ticket}&pgtIou=#{pgt.iou}"
|
||||
|
||||
|
||||
response = conn.request_get(path)
|
||||
# TODO: follow redirects... 2.5.4 says that redirects MAY be followed
|
||||
# NOTE: The following response codes are valid according to the JA-SIG implementation even without following redirects
|
||||
|
@ -111,10 +111,10 @@ module CASServer::CAS
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def validate_login_ticket(ticket)
|
||||
$LOG.debug("Validating login ticket '#{ticket}'")
|
||||
|
||||
|
||||
success = false
|
||||
if ticket.nil?
|
||||
error = _("Your login request did not include a login ticket. There may be a problem with the authentication system.")
|
||||
|
@ -133,15 +133,15 @@ module CASServer::CAS
|
|||
error = _("The login ticket you provided is invalid. There may be a problem with the authentication system.")
|
||||
$LOG.warn "Invalid login ticket '#{ticket}'"
|
||||
end
|
||||
|
||||
|
||||
lt.consume! if lt
|
||||
|
||||
|
||||
error
|
||||
end
|
||||
|
||||
|
||||
def validate_ticket_granting_ticket(ticket)
|
||||
$LOG.debug("Validating ticket granting ticket '#{ticket}'")
|
||||
|
||||
|
||||
if ticket.nil?
|
||||
error = "No ticket granting ticket given."
|
||||
$LOG.debug error
|
||||
|
@ -156,13 +156,13 @@ module CASServer::CAS
|
|||
error = "Invalid ticket granting ticket '#{ticket}' (no matching ticket found in the database)."
|
||||
$LOG.warn(error)
|
||||
end
|
||||
|
||||
|
||||
[tgt, error]
|
||||
end
|
||||
|
||||
def validate_service_ticket(service, ticket, allow_proxy_tickets = false)
|
||||
$LOG.debug "Validating service/proxy ticket '#{ticket}' for service '#{service}'"
|
||||
|
||||
|
||||
if service.nil? or ticket.nil?
|
||||
error = Error.new(:INVALID_REQUEST, "Ticket or service parameter was missing in the request.")
|
||||
$LOG.warn "#{error.code} - #{error.message}"
|
||||
|
@ -187,18 +187,18 @@ module CASServer::CAS
|
|||
error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' not recognized.")
|
||||
$LOG.warn("#{error.code} - #{error.message}")
|
||||
end
|
||||
|
||||
|
||||
if st
|
||||
st.consume!
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
[st, error]
|
||||
end
|
||||
|
||||
|
||||
def validate_proxy_ticket(service, ticket)
|
||||
pt, error = validate_service_ticket(service, ticket, true)
|
||||
|
||||
|
||||
if pt.kind_of?(CASServer::Models::ProxyTicket) && !error
|
||||
if not pt.granted_by_pgt
|
||||
error = Error.new(:INTERNAL_ERROR, "Proxy ticket '#{pt}' belonging to user '#{pt.username}' is not associated with a proxy granting ticket.")
|
||||
|
@ -207,10 +207,10 @@ module CASServer::CAS
|
|||
" (associated with proxy ticket '#{pt}' and belonging to user '#{pt.username}' is not associated with a service ticket.")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
[pt, error]
|
||||
end
|
||||
|
||||
|
||||
def validate_proxy_granting_ticket(ticket)
|
||||
if ticket.nil?
|
||||
error = Error.new(:INVALID_REQUEST, "pgt parameter was missing in the request.")
|
||||
|
@ -226,10 +226,10 @@ module CASServer::CAS
|
|||
error = Error.new(:BAD_PGT, "Invalid proxy granting ticket '#{ticket}' (no matching ticket found in the database).")
|
||||
$LOG.warn("#{error.code} - #{error.message}")
|
||||
end
|
||||
|
||||
|
||||
[pgt, error]
|
||||
end
|
||||
|
||||
|
||||
# Takes an existing ServiceTicket object (presumably pulled from the database)
|
||||
# and sends a POST with logout information to the service that the ticket
|
||||
# was generated for.
|
||||
|
@ -240,13 +240,13 @@ module CASServer::CAS
|
|||
uri = URI.parse(st.service)
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
#http.use_ssl = true if uri.scheme = 'https'
|
||||
|
||||
|
||||
time = Time.now
|
||||
rand = CASServer::Utils.random_string
|
||||
|
||||
|
||||
path = uri.path
|
||||
path = '/' if path.empty?
|
||||
|
||||
|
||||
req = Net::HTTP::Post.new(path)
|
||||
req.set_form_data(
|
||||
'logoutRequest' => %{<samlp:LogoutRequest ID="#{rand}" Version="2.0" IssueInstant="#{time.rfc2822}">
|
||||
|
@ -254,11 +254,11 @@ module CASServer::CAS
|
|||
<samlp:SessionIndex>#{st.ticket}</samlp:SessionIndex>
|
||||
</samlp:LogoutRequest>}
|
||||
)
|
||||
|
||||
|
||||
begin
|
||||
http.start do |conn|
|
||||
response = conn.request(req)
|
||||
|
||||
|
||||
if response.kind_of? Net::HTTPSuccess
|
||||
$LOG.info "Logout notification successfully posted to #{st.service.inspect}."
|
||||
return true
|
||||
|
@ -272,14 +272,14 @@ module CASServer::CAS
|
|||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def service_uri_with_ticket(service, st)
|
||||
raise ArgumentError, "Second argument must be a ServiceTicket!" unless st.kind_of? CASServer::Models::ServiceTicket
|
||||
|
||||
|
||||
# This will choke with a URI::InvalidURIError if service URI is not properly URI-escaped...
|
||||
# This exception is handled further upstream (i.e. in the controller).
|
||||
service_uri = URI.parse(service)
|
||||
|
||||
|
||||
if service.include? "?"
|
||||
if service_uri.query.empty?
|
||||
query_separator = ""
|
||||
|
@ -289,11 +289,11 @@ module CASServer::CAS
|
|||
else
|
||||
query_separator = "?"
|
||||
end
|
||||
|
||||
|
||||
service_with_ticket = service + query_separator + "ticket=" + st.ticket
|
||||
service_with_ticket
|
||||
end
|
||||
|
||||
|
||||
# Strips CAS-related parameters from a service URL and normalizes it,
|
||||
# removing trailing / and ?. Also converts any spaces to +.
|
||||
#
|
||||
|
@ -310,16 +310,16 @@ module CASServer::CAS
|
|||
['service', 'ticket', 'gateway', 'renew'].each do |p|
|
||||
clean_service.sub!(Regexp.new("&?#{p}=[^&]*"), '')
|
||||
end
|
||||
|
||||
|
||||
clean_service.gsub!(/[\/\?&]$/, '') # remove trailing ?, /, or &
|
||||
clean_service.gsub!('?&', '?')
|
||||
clean_service.gsub!(' ', '+')
|
||||
|
||||
|
||||
$LOG.debug("Cleaned dirty service URL #{dirty_service.inspect} to #{clean_service.inspect}") if
|
||||
dirty_service != clean_service
|
||||
|
||||
|
||||
return clean_service
|
||||
end
|
||||
module_function :clean_service_url
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
require 'active_support'
|
||||
|
||||
conf_defaults = {
|
||||
:maximum_unused_login_ticket_lifetime => 5.minutes,
|
||||
:maximum_unused_service_ticket_lifetime => 5.minutes, # CAS Protocol Spec, sec. 3.2.1 (recommended expiry time)
|
||||
|
@ -29,7 +32,7 @@ unless $CONF[:authenticator]
|
|||
your config file.
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
"
|
||||
"
|
||||
raise Picnic::Conf::Error, err
|
||||
end
|
||||
|
||||
|
@ -39,6 +42,7 @@ begin
|
|||
$CONF[:authenticator].each { |authenticator| $AUTH << authenticator[:class].constantize}
|
||||
else
|
||||
$AUTH << $CONF[:authenticator][:class].constantize
|
||||
$CONF[:authenticator] = [$CONF[:authenticator]]
|
||||
end
|
||||
rescue NameError
|
||||
if $CONF[:authenticator].instance_of? Array
|
||||
|
@ -52,7 +56,6 @@ rescue NameError
|
|||
require 'casserver/'+auth_rb
|
||||
end
|
||||
$AUTH << authenticator[:class].constantize
|
||||
$CONF[:authenticator] = [$CONF[:authenticator]]
|
||||
end
|
||||
else
|
||||
if $CONF[:authenticator][:source]
|
||||
|
|
|
@ -7,7 +7,7 @@ elsif File.exists?(picnic = File.expand_path(File.dirname(File.expand_path(__FIL
|
|||
else
|
||||
puts "Loading picnic from rubygems..."
|
||||
require 'rubygems'
|
||||
|
||||
|
||||
begin
|
||||
# Try to load dev version of picnic if available (for example 'zuk-picnic' from Github)
|
||||
gem /^.*?-picnic$/
|
||||
|
|
|
@ -4,13 +4,13 @@ require "gettext/cgi"
|
|||
module CASServer
|
||||
include GetText
|
||||
bindtextdomain("rubycas-server", :path => File.join(File.dirname(File.expand_path(__FILE__)), "../../locale"))
|
||||
|
||||
|
||||
def service(*a)
|
||||
GetText.locale = determine_locale
|
||||
#puts GetText.locale.inspect
|
||||
super(*a)
|
||||
end
|
||||
|
||||
|
||||
def determine_locale
|
||||
|
||||
source = nil
|
||||
|
@ -39,7 +39,7 @@ module CASServer
|
|||
$LOG.debug "Detected locale is #{lang.inspect} (from #{source})"
|
||||
|
||||
lang.gsub!('_','-')
|
||||
|
||||
|
||||
# TODO: Need to confirm that this method of splitting the accepted
|
||||
# language string is correct.
|
||||
if lang =~ /[,;\|]/
|
||||
|
@ -47,35 +47,36 @@ module CASServer
|
|||
else
|
||||
langs = [lang]
|
||||
end
|
||||
|
||||
|
||||
# TODO: This method of selecting the desired language might not be
|
||||
# standards-compliant. For example, http://www.w3.org/TR/ltli/
|
||||
# suggests that de-de and de-*-DE might be acceptable identifiers
|
||||
# for selecting various wildcards. The algorithm below does not
|
||||
# currently support anything like this.
|
||||
|
||||
|
||||
available = available_locales
|
||||
|
||||
|
||||
# Try to pick a locale exactly matching the desired identifier, otherwise
|
||||
# fall back to locale without region (i.e. given "en-US; de-DE", we would
|
||||
# first look for "en-US", then "en", then "de-DE", then "de").
|
||||
|
||||
|
||||
chosen_lang = nil
|
||||
langs.each do |l|
|
||||
a = available.find{|a| a == l || a =~ Regexp.new("#{l}-\w*")}
|
||||
langs.each do |l|
|
||||
a = available.find{ |a| a =~ Regexp.new("\\A#{l}\\Z", 'i') ||
|
||||
a =~ Regexp.new("#{l}-\w*", 'i') }
|
||||
if a
|
||||
chosen_lang = a
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
chosen_lang = "en" if chosen_lang.blank?
|
||||
|
||||
$LOG.debug "Chosen locale is #{chosen_lang.inspect}"
|
||||
|
||||
|
||||
return chosen_lang
|
||||
end
|
||||
|
||||
|
||||
def available_locales
|
||||
(Dir.glob(File.join(File.dirname(File.expand_path(__FILE__)), "../../locale/[a-z]*")).map{|path| File.basename(path)} << "en").uniq.collect{|l| l.gsub('_','-')}
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'camping/ar'
|
||||
|
||||
module CASServer::Models
|
||||
|
||||
|
||||
module Consumable
|
||||
def consume!
|
||||
self.consumed = Time.now
|
||||
|
@ -15,7 +15,7 @@ module CASServer::Models
|
|||
module ClassMethods
|
||||
def cleanup(max_lifetime, max_unconsumed_lifetime)
|
||||
transaction do
|
||||
conditions = ["created_on < ? OR (consumed IS NULL AND created_on < ?)",
|
||||
conditions = ["created_on < ? OR (consumed IS NULL AND created_on < ?)",
|
||||
Time.now - max_lifetime,
|
||||
Time.now - max_unconsumed_lifetime]
|
||||
expired_tickets_count = count(:conditions => conditions)
|
||||
|
@ -28,78 +28,78 @@ module CASServer::Models
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class Ticket < Base
|
||||
def to_s
|
||||
ticket
|
||||
end
|
||||
|
||||
|
||||
def self.cleanup(max_lifetime)
|
||||
transaction do
|
||||
conditions = ["created_on < ?", Time.now - max_lifetime]
|
||||
expired_tickets_count = count(:conditions => conditions)
|
||||
|
||||
|
||||
$LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.demodulize}"+
|
||||
"#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0
|
||||
|
||||
|
||||
destroy_all(conditions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class LoginTicket < Ticket
|
||||
set_table_name 'casserver_lt'
|
||||
include Consumable
|
||||
end
|
||||
|
||||
|
||||
class ServiceTicket < Ticket
|
||||
set_table_name 'casserver_st'
|
||||
include Consumable
|
||||
|
||||
belongs_to :granted_by_tgt,
|
||||
|
||||
belongs_to :granted_by_tgt,
|
||||
:class_name => 'CASServer::Models::TicketGrantingTicket',
|
||||
:foreign_key => :granted_by_tgt_id
|
||||
has_one :proxy_granting_ticket,
|
||||
:foreign_key => :created_by_st_id
|
||||
|
||||
|
||||
def matches_service?(service)
|
||||
CASServer::CAS.clean_service_url(self.service) ==
|
||||
CASServer::CAS.clean_service_url(self.service) ==
|
||||
CASServer::CAS.clean_service_url(service)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class ProxyTicket < ServiceTicket
|
||||
belongs_to :granted_by_pgt,
|
||||
:class_name => 'CASServer::Models::ProxyGrantingTicket',
|
||||
:foreign_key => :granted_by_pgt_id
|
||||
end
|
||||
|
||||
|
||||
class TicketGrantingTicket < Ticket
|
||||
set_table_name 'casserver_tgt'
|
||||
|
||||
|
||||
serialize :extra_attributes
|
||||
|
||||
has_many :granted_service_tickets,
|
||||
|
||||
has_many :granted_service_tickets,
|
||||
:class_name => 'CASServer::Models::ServiceTicket',
|
||||
:foreign_key => :granted_by_tgt_id
|
||||
end
|
||||
|
||||
|
||||
class ProxyGrantingTicket < Ticket
|
||||
set_table_name 'casserver_pgt'
|
||||
belongs_to :service_ticket
|
||||
has_many :granted_proxy_tickets,
|
||||
has_many :granted_proxy_tickets,
|
||||
:class_name => 'CASServer::Models::ProxyTicket',
|
||||
:foreign_key => :granted_by_pgt_id
|
||||
end
|
||||
|
||||
|
||||
class Error
|
||||
attr_reader :code, :message
|
||||
|
||||
|
||||
def initialize(code, message)
|
||||
@code = code
|
||||
@message = message
|
||||
end
|
||||
|
||||
|
||||
def to_s
|
||||
message
|
||||
end
|
||||
|
@ -109,14 +109,14 @@ module CASServer::Models
|
|||
def self.up
|
||||
if ActiveRecord::Base.connection.table_alias_length > 30
|
||||
$LOG.info("Creating database with long table names...")
|
||||
|
||||
|
||||
create_table :casserver_login_tickets, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :created_on, :timestamp, :null => false
|
||||
t.column :consumed, :datetime, :null => true
|
||||
t.column :client_hostname, :string, :null => false
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_service_tickets, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :service, :string, :null => false
|
||||
|
@ -127,14 +127,14 @@ module CASServer::Models
|
|||
t.column :type, :string, :null => false
|
||||
t.column :proxy_granting_ticket_id, :integer, :null => true
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_ticket_granting_tickets, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :created_on, :timestamp, :null => false
|
||||
t.column :client_hostname, :string, :null => false
|
||||
t.column :username, :string, :null => false
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_proxy_granting_tickets, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :created_on, :timestamp, :null => false
|
||||
|
@ -144,7 +144,7 @@ module CASServer::Models
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
if ActiveRecord::Base.connection.table_alias_length > 30
|
||||
drop_table :casserver_proxy_granting_tickets
|
||||
|
@ -154,8 +154,8 @@ module CASServer::Models
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Oracle table names cannot exceed 30 chars...
|
||||
|
||||
# Oracle table names cannot exceed 30 chars...
|
||||
# See http://code.google.com/p/rubycas-server/issues/detail?id=15
|
||||
class ShortenTableNames < V 0.5
|
||||
def self.up
|
||||
|
@ -172,7 +172,7 @@ module CASServer::Models
|
|||
t.column :consumed, :datetime, :null => true
|
||||
t.column :client_hostname, :string, :null => false
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_st, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :service, :string, :null => false
|
||||
|
@ -183,14 +183,14 @@ module CASServer::Models
|
|||
t.column :type, :string, :null => false
|
||||
t.column :proxy_granting_ticket_id, :integer, :null => true
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_tgt, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :created_on, :timestamp, :null => false
|
||||
t.column :client_hostname, :string, :null => false
|
||||
t.column :username, :string, :null => false
|
||||
end
|
||||
|
||||
|
||||
create_table :casserver_pgt, :force => true do |t|
|
||||
t.column :ticket, :string, :null => false
|
||||
t.column :created_on, :timestamp, :null => false
|
||||
|
@ -200,7 +200,7 @@ module CASServer::Models
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
if ActiveRecord::Base.connection.table_alias_length > 30
|
||||
rename_table :casserver_lt, :cassserver_login_tickets
|
||||
|
@ -215,17 +215,17 @@ module CASServer::Models
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class AddTgtToSt < V 0.7
|
||||
def self.up
|
||||
add_column :casserver_st, :tgt_id, :integer, :null => true
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
remove_column :casserver_st, :tgt_id, :integer
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class ChangeServiceToText < V 0.71
|
||||
def self.up
|
||||
# using change_column to change the column type from :string to :text
|
||||
|
@ -235,17 +235,17 @@ module CASServer::Models
|
|||
say "WARNING: All existing service tickets are being deleted."
|
||||
add_column :casserver_st, :service, :text
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
change_column :casserver_st, :service, :string
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class AddExtraAttributes < V 0.72
|
||||
def self.up
|
||||
add_column :casserver_tgt, :extra_attributes, :text
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
remove_column :casserver_tgt, :extra_attributes
|
||||
end
|
||||
|
|
|
@ -1,50 +1,50 @@
|
|||
module CASServer
|
||||
module Postambles
|
||||
|
||||
|
||||
def webrick
|
||||
require 'webrick/httpserver'
|
||||
require 'webrick/https'
|
||||
require 'camping/webrick'
|
||||
|
||||
|
||||
# TODO: verify the certificate's validity
|
||||
# example of how to do this is here: http://pablotron.org/download/ruri-20050331.rb
|
||||
|
||||
|
||||
cert_path = $CONF.ssl_cert
|
||||
key_path = $CONF.ssl_key || $CONF.ssl_cert
|
||||
# look for the key in the ssl_cert if no ssl_key is specified
|
||||
|
||||
|
||||
webrick_options = {:BindAddress => "0.0.0.0", :Port => $CONF.port}
|
||||
|
||||
|
||||
unless cert_path.nil? && key_path.nil?
|
||||
raise "'#{cert_path}' is not a valid ssl certificate. Your 'ssl_cert' configuration" +
|
||||
" setting must be a path to a valid ssl certificate file." unless
|
||||
File.exists? cert_path
|
||||
|
||||
|
||||
raise "'#{key_path}' is not a valid ssl private key. Your 'ssl_key' configuration" +
|
||||
" setting must be a path to a valid ssl private key file." unless
|
||||
File.exists? key_path
|
||||
|
||||
|
||||
cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
||||
key = OpenSSL::PKey::RSA.new(File.read(key_path))
|
||||
|
||||
|
||||
webrick_options[:SSLEnable] = true
|
||||
webrick_options[:SSLVerifyClient] = ::OpenSSL::SSL::VERIFY_NONE
|
||||
webrick_options[:SSLCertificate] = cert
|
||||
webrick_options[:SSLPrivateKey] = key
|
||||
end
|
||||
|
||||
|
||||
begin
|
||||
s = WEBrick::HTTPServer.new(webrick_options)
|
||||
rescue Errno::EACCES
|
||||
puts "\nThe server could not launch. Are you running on a privileged port? (e.g. port 443) If so, you must run the server as root."
|
||||
exit 2
|
||||
end
|
||||
|
||||
|
||||
CASServer.create
|
||||
s.mount "#{$CONF.uri_path}", WEBrick::CampingHandler, CASServer
|
||||
|
||||
|
||||
puts "\n** CASServer is running at http#{webrick_options[:SSLEnable] ? 's' : ''}://#{Socket.gethostname}:#{$CONF.port}#{$CONF.uri_path} and logging to '#{$CONF.log[:file]}'\n\n"
|
||||
|
||||
|
||||
# This lets Ctrl+C shut down your server
|
||||
trap(:INT) do
|
||||
s.shutdown
|
||||
|
@ -52,7 +52,7 @@ module CASServer
|
|||
trap(:TERM) do
|
||||
s.shutdown
|
||||
end
|
||||
|
||||
|
||||
if $DAEMONIZE
|
||||
WEBrick::Daemon.start do
|
||||
write_pid_file if $PID_FILE
|
||||
|
@ -63,33 +63,33 @@ module CASServer
|
|||
s.start
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def mongrel
|
||||
require 'rubygems'
|
||||
require 'mongrel/camping'
|
||||
|
||||
|
||||
if $DAEMONIZE
|
||||
# check if log and pid are writable before daemonizing, otherwise we won't be able to notify
|
||||
# the user if we run into trouble later (since once daemonized, we can't write to stdout/stderr)
|
||||
check_pid_writable if $PID_FILE
|
||||
check_log_writable
|
||||
end
|
||||
|
||||
|
||||
CASServer.create
|
||||
|
||||
|
||||
puts "\n** CASServer is starting. Look in '#{$CONF.log[:file]}' for further notices."
|
||||
|
||||
|
||||
settings = {:host => "0.0.0.0", :log_file => $CONF.log[:file], :cwd => $CASSERVER_HOME}
|
||||
|
||||
|
||||
# need to close all IOs before daemonizing
|
||||
$LOG.close if $DAEMONIZE
|
||||
|
||||
|
||||
begin
|
||||
config = Mongrel::Configurator.new settings do
|
||||
daemonize :log_file => $CONF.log[:file], :cwd => $CASSERVER_HOME if $DAEMONIZE
|
||||
|
||||
|
||||
listener :port => $CONF.port do
|
||||
uri $CONF.uri_path, :handler => Mongrel::Camping::CampingHandler.new(CASServer)
|
||||
setup_signals
|
||||
|
@ -98,12 +98,12 @@ module CASServer
|
|||
rescue Errno::EADDRINUSE
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
||||
config.run
|
||||
|
||||
|
||||
CASServer.init_logger
|
||||
CASServer.init_db_logger
|
||||
|
||||
|
||||
if $DAEMONIZE && $PID_FILE
|
||||
write_pid_file
|
||||
unless File.exists? $PID_FILE
|
||||
|
@ -111,7 +111,7 @@ module CASServer
|
|||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
puts "\n** CASServer is running at http://localhost:#{$CONF.port}#{$CONF.uri_path} and logging to '#{$CONF.log[:file]}'"
|
||||
config.join
|
||||
|
||||
|
@ -119,22 +119,22 @@ module CASServer
|
|||
|
||||
puts "\n** CASServer is stopped (#{Time.now})"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def fastcgi
|
||||
require 'camping/fastcgi'
|
||||
Dir.chdir('/srv/www/camping/casserver/')
|
||||
|
||||
|
||||
CASServer.create
|
||||
Camping::FastCGI.start(CASServer)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def cgi
|
||||
CASServer.create
|
||||
puts CASServer.run
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def check_log_writable
|
||||
log_file = $CONF.log['file']
|
||||
|
@ -146,10 +146,10 @@ module CASServer
|
|||
end
|
||||
f.close
|
||||
end
|
||||
|
||||
|
||||
def check_pid_writable
|
||||
$LOG.debug "Checking if pid file '#{$PID_FILE}' is writable"
|
||||
begin
|
||||
begin
|
||||
f = open($PID_FILE, 'w')
|
||||
rescue
|
||||
$stderr.puts "Couldn't write to log at '#{$PID_FILE}' (#{$!})."
|
||||
|
@ -157,18 +157,18 @@ module CASServer
|
|||
end
|
||||
f.close
|
||||
end
|
||||
|
||||
|
||||
def write_pid_file
|
||||
$LOG.debug "Writing pid '#{Process.pid}' to pid file '#{$PID_FILE}'"
|
||||
open($PID_FILE, "w") { |file| file.write(Process.pid) }
|
||||
end
|
||||
|
||||
|
||||
def clear_pid_file
|
||||
if $PID_FILE && File.exists?($PID_FILE)
|
||||
$LOG.debug "Clearing pid file '#{$PID_FILE}'"
|
||||
File.unlink $PID_FILE
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,19 +4,19 @@ module CASServer
|
|||
def random_string(max_length = 29)
|
||||
rg = Crypt::ISAAC.new
|
||||
max = 4294619050
|
||||
r = "#{Time.now.to_i}r%X%X%X%X%X%X%X%X" %
|
||||
[rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max),
|
||||
r = "#{Time.now.to_i}r%X%X%X%X%X%X%X%X" %
|
||||
[rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max),
|
||||
rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max)]
|
||||
r[0..max_length-1]
|
||||
end
|
||||
module_function :random_string
|
||||
|
||||
|
||||
def log_controller_action(controller, params)
|
||||
$LOG << "\n"
|
||||
|
||||
|
||||
/`(.*)'/.match(caller[1])
|
||||
method = $~[1]
|
||||
|
||||
|
||||
if params.respond_to? :dup
|
||||
params2 = params.dup
|
||||
params2['password'] = '******' if params2['password']
|
||||
|
@ -27,4 +27,4 @@ module CASServer
|
|||
end
|
||||
module_function :log_controller_action
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Markaby::Builder.set(:auto_validation, false)
|
||||
|
||||
# disabled XML indentation because it was causing problems with mod_auth_cas
|
||||
#Markaby::Builder.set(:indent, 2)
|
||||
#Markaby::Builder.set(:indent, 2)
|
||||
|
||||
module CASServer::Views
|
||||
|
||||
|
@ -13,7 +13,7 @@ module CASServer::Views
|
|||
# wrap as XHTML only when auto_validation is on, otherwise pass right through
|
||||
if @use_layout
|
||||
xhtml_strict do
|
||||
head do
|
||||
head do
|
||||
title { "#{organization} #{_(' Central Login')}" }
|
||||
link(:rel => "stylesheet", :type => "text/css", :href => "/themes/cas.css")
|
||||
link(:rel => "stylesheet", :type => "text/css", :href => "/themes/#{current_theme}/theme.css")
|
||||
|
@ -21,7 +21,7 @@ module CASServer::Views
|
|||
File.exists?("#{$APP_ROOT}/public/themes/#{current_theme}/favicon.png")
|
||||
end
|
||||
body(:onload => "if (document.getElementById('username')) document.getElementById('username').focus()") do
|
||||
self << yield
|
||||
self << yield
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -34,7 +34,7 @@ module CASServer::Views
|
|||
# The full login page.
|
||||
def login
|
||||
@use_layout = true
|
||||
|
||||
|
||||
table(:id => "login-box") do
|
||||
tr do
|
||||
td(:colspan => 2) do
|
||||
|
@ -62,11 +62,12 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Just the login form.
|
||||
def login_form
|
||||
submitbutton = _("Please wait...")
|
||||
form(:method => "post", :action => @form_action || '/login', :id => "login-form",
|
||||
:onsubmit => "submitbutton = document.getElementById('login-submit'); submitbutton.value='#{ _("Please wait...") }'; submitbutton.disabled=true; return true;") do
|
||||
:onsubmit => "submitbutton = document.getElementById('login-submit'); submitbutton.value='#{submitbutton}'; submitbutton.disabled=true; return true;") do
|
||||
table(:id => "form-layout") do
|
||||
tr do
|
||||
td(:id => "username-label-container") do
|
||||
|
@ -82,7 +83,7 @@ module CASServer::Views
|
|||
label(:id => "password-label", :for => "password") { _( "Password" ) }
|
||||
end
|
||||
td(:id => "password-container") do
|
||||
input(:type => "password", :id => "password", :name => "password",
|
||||
input(:type => "password", :id => "password", :name => "password",
|
||||
:size => "32", :tabindex => "2", :accesskey => "p", :autocomplete => "off")
|
||||
end
|
||||
end
|
||||
|
@ -100,11 +101,11 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# 2.3.2
|
||||
def logout
|
||||
@use_layout = true
|
||||
|
||||
|
||||
table(:id => "login-box") do
|
||||
tr do
|
||||
td(:colspan => 2) do
|
||||
|
@ -128,7 +129,7 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# 2.4.2
|
||||
# CAS 1.0 validate response.
|
||||
def validate
|
||||
|
@ -138,7 +139,7 @@ module CASServer::Views
|
|||
text "no\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# 2.5.2
|
||||
# CAS 2.0 service validate response.
|
||||
def service_validate
|
||||
|
@ -160,7 +161,7 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# 2.6.2
|
||||
# CAS 2.0 proxy validate response.
|
||||
def proxy_validate
|
||||
|
@ -189,7 +190,7 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# 2.7.2
|
||||
# CAS 2.0 proxy request response.
|
||||
def proxy
|
||||
|
@ -205,31 +206,31 @@ module CASServer::Views
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def configure
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def themes_dir
|
||||
File.dirname(File.expand_path(__FILE__))+'../themes'
|
||||
end
|
||||
module_function :themes_dir
|
||||
|
||||
|
||||
def current_theme
|
||||
$CONF.theme || "simple"
|
||||
end
|
||||
module_function :current_theme
|
||||
|
||||
|
||||
def organization
|
||||
$CONF.organization || ""
|
||||
end
|
||||
module_function :organization
|
||||
|
||||
|
||||
def infoline
|
||||
$CONF.infoline || ""
|
||||
end
|
||||
module_function :infoline
|
||||
|
||||
|
||||
def serialize_extra_attribute(value)
|
||||
if value.kind_of?(String) || value.kind_of?(Numeric)
|
||||
value
|
||||
|
|
|
@ -1 +1 @@
|
|||
require File.dirname(__FILE__)+'/casserver'
|
||||
require File.dirname(__FILE__)+'/casserver'
|
||||
|
|
|
@ -1 +1 @@
|
|||
require File.dirname(__FILE__)+'/../casserver/version.rb'
|
||||
require File.dirname(__FILE__)+'/../casserver/version.rb'
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-12 12:49-0500\n"
|
||||
"Last-Translator: Matt Zukowski <mzukowski@urbacon.net>\n"
|
||||
"Language-Team: German\n"
|
||||
|
@ -62,7 +62,7 @@ msgstr ""
|
|||
"Der Server kann diese Gateway-Anfrage nicht erfüllen, da keine Service-"
|
||||
"Parameter übergeben wurden."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -79,41 +79,49 @@ msgstr ""
|
|||
"Der CAS-Login-URI konnte nicht erraten werden. Bitte ergänzen Sie Ihre "
|
||||
"Anfrage um einen submitToURI Parameter."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr ""
|
||||
"Sie haben sich erfolgreich am Central Authentication Service angemeldet."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Falscher Benutzername oder Passwort."
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr ""
|
||||
"Sie haben sich erfolgreich vom Central Authentication Service abgemeldet."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " Bitte klicken Sie auf den folgenden Link, um fortzufahren:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr ""
|
||||
"Für die Generierung eines Login-Tickets, ist eine POST-Anfrage erforderlich."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Zentrales Login"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Benutzername"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "ANMELDEN"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-12 12:30-0500\n"
|
||||
"Last-Translator: Matt Zukowski <mzukowski@urbacon.net>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
|
@ -61,7 +61,7 @@ msgstr ""
|
|||
"El servidor no puede cumplir con esta petición, porque no fue parámetro de "
|
||||
"servicio prestado."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -78,38 +78,46 @@ msgstr ""
|
|||
"No podía adivinar el URI de acceso CAS. Suministro submitToURI un parámetro "
|
||||
"con su solicitud."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr "Inicio de sesión satisfactorio."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Incorrecto nombre de usuario o contraseña."
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "Cierre de sesión satisfactorio."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " Por favor, haga clic en el vínculo siguiente para continuar:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr "Para generar un ticket de acceso, usted debe hacer una petición POST."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Servicio de Autenticación Central"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Usuario"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "INICIAR SESIÓN"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-12 11:53-0500\n"
|
||||
"Last-Translator: Matt Zukowski <mzukowski@urbacon.net>\n"
|
||||
"Language-Team: French\n"
|
||||
|
@ -61,7 +61,7 @@ msgstr ""
|
|||
"Le serveur ne peut pas répondre à cette demande (pas de 'service' paramètre "
|
||||
"a été donné)."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -77,40 +77,48 @@ msgstr ""
|
|||
"Impossible de deviner le CAS de connexion URI. S'il vous plaît fournir une "
|
||||
"submitToURI paramètre à votre demande."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr ""
|
||||
"Vous vous êtes authentifié(e) auprès du Service Central d'Authentification."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Les informations transmises n'ont pas permis de vous authentifier"
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "Vous vous êtes déconnecté(e) du Service Central d'Authentification."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " S'il vous plaît cliquer sur le lien suivant pour continuer:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr ""
|
||||
"Pour générer un ticket de connexion, vous devez faire une requête POST."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Service Central d'Authentification."
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Identifiant"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "SE CONNECTER"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-12 13:04-0500\n"
|
||||
"Last-Translator: Matt Zukowski <mzukowski@urbacon.net>\n"
|
||||
"Language-Team: Japanese\n"
|
||||
|
@ -65,7 +65,7 @@ msgstr ""
|
|||
"サービスパラメーターが指定されていないので、サーバーはゲートウェイリクエスト"
|
||||
"を満たす事ができません。"
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -81,38 +81,46 @@ msgstr ""
|
|||
"CASのURIを推測することができませんでした。リクエストにsubmitToURIパラメータを"
|
||||
"指定してください。"
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr "ログインしました"
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "ユーザー名またはパスワードが間違っています"
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "ログアウトしました。"
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " 継続するには、以下のリンクをクリックしてください:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr "ログインチケットを発行するには、POSTリクエストを送る必要があります。"
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " 統合ログイン"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "ユーザー名"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "パスワード"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "ログイン"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-12 11:03-0500\n"
|
||||
"Last-Translator: Matt Zukowski <mzukowski@urbacon.net>\n"
|
||||
"Language-Team: Polish\n"
|
||||
|
@ -62,7 +62,7 @@ msgstr ""
|
|||
"Serwer nie może spełnić tego żądania bramowego, ponieważ nie został podany "
|
||||
"parametr usługi."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -78,38 +78,46 @@ msgstr ""
|
|||
"Nie można odgadnąć URI do logowania do CAS. Proszę dostarczyć parametr "
|
||||
"submitToURI."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr "Jesteś zalogowany."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Niepoprawny użytkownik lub hasło."
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "Jesteś wylogowany."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " Proszę kliknąć na poniższy link, aby kontynuować:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr "Aby wygenerować login bilet, musisz złożyć żądanie POST."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Centralna Usługa Uwierzytelniania"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Użytkownik"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Hasło"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "ZALOGUJ"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2009-03-17 20:55+0200\n"
|
||||
"Last-Translator: Kivanio Barbosa <kivanio@gmail.com>\n"
|
||||
"Language-Team: Brazil\n"
|
||||
|
@ -61,7 +61,7 @@ msgstr ""
|
|||
"O servidor não pode completar a solicitação porque não foi enviado o "
|
||||
"paramêtro do serviço."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -77,39 +77,47 @@ msgstr ""
|
|||
"Não encontramos a URI de acesso ao CAS. Por favor, informe corretamente no "
|
||||
"submitToURI com sua solicitação."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr "Login efetuado com sucesso."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Usuário ou Senha está incorreto."
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "Você saiu do sistema com sucesso."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " Por favor, clique no seguinte link para continuar:"
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr ""
|
||||
"Para gerar um ticket de acceso, você deve fazer uma requisição via POST."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Central de Autenticação"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Usuário"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "ENTRAR"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-11-04 12:32+0200\n"
|
||||
"Last-Translator: Antono Vasiljev <antono.vasiljev@gmail.com>\n"
|
||||
"Language-Team: Russian <ru@li.org>\n"
|
||||
|
@ -57,7 +57,7 @@ msgstr ""
|
|||
"Этот сервер не может выполнить этот запрос, поскольку не были указаны "
|
||||
"праметры сервиса."
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -73,38 +73,46 @@ msgstr ""
|
|||
"Не возможно угадать адрес входа на CAS. Пожалуйста, передайте с запросом "
|
||||
"параметр submitToURI."
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr "Вы успешно вошли."
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr "Неверное имя пользователя или пароль."
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr "Вы успешно вышли."
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr " Перейдите по ссылке чтобы продолжить: "
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr "Чтобы сгенерировать входной билет вы должны делать POST запрос."
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " Центральный вход"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "Логин"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "Войти"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-05-06 18:16-0400\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2008-10-29 20:55+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -55,7 +55,7 @@ msgid ""
|
|||
"was given."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:195
|
||||
#: lib/casserver/controllers.rb:59 lib/casserver/controllers.rb:179
|
||||
msgid ""
|
||||
"The target service your browser supplied appears to be invalid. Please "
|
||||
"contact your system administrator for help."
|
||||
|
@ -67,38 +67,46 @@ msgid ""
|
|||
"with your request."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:184
|
||||
#: lib/casserver/controllers.rb:168
|
||||
msgid "You have successfully logged in."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:200
|
||||
#: lib/casserver/controllers.rb:184
|
||||
msgid "Incorrect username or password."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:257
|
||||
#: lib/casserver/controllers.rb:267
|
||||
msgid "You have successfully logged out."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:260
|
||||
#: lib/casserver/controllers.rb:269
|
||||
msgid " Please click on the following link to continue:"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/controllers.rb:410
|
||||
#: lib/casserver/controllers.rb:419
|
||||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:113
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:94
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr ""
|
||||
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr ""
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: rubycas-server \n"
|
||||
"POT-Creation-Date: 2009-09-29 16:29+0800\n"
|
||||
"POT-Creation-Date: 2009-09-29 17:04+0800\n"
|
||||
"PO-Revision-Date: 2009-03-17 20:55+0200\n"
|
||||
"Last-Translator: Lin Jen-Shin <godfat@godfat.org>\n"
|
||||
"Language-Team: Traditional Chinese\n"
|
||||
|
@ -87,23 +87,27 @@ msgstr " 請點以下的連結繼續"
|
|||
msgid "To generate a login ticket, you must make a POST request."
|
||||
msgstr "你必須使用 POST 來產生登入憑証"
|
||||
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:119
|
||||
#: lib/casserver/views.rb:43 lib/casserver/views.rb:120
|
||||
msgid " Central Login"
|
||||
msgstr " 整合登入"
|
||||
|
||||
#: lib/casserver/views.rb:73
|
||||
#: lib/casserver/views.rb:68
|
||||
msgid "Please wait..."
|
||||
msgstr "請稍候..."
|
||||
|
||||
#: lib/casserver/views.rb:74
|
||||
msgid "Username"
|
||||
msgstr "帳號"
|
||||
|
||||
#: lib/casserver/views.rb:82
|
||||
#: lib/casserver/views.rb:83
|
||||
msgid "Password"
|
||||
msgstr "密碼"
|
||||
|
||||
#: lib/casserver/views.rb:91
|
||||
#: lib/casserver/views.rb:92
|
||||
msgid "Remeber me on this computer"
|
||||
msgstr "在這台電腦上記住我"
|
||||
|
||||
#: lib/casserver/views.rb:100
|
||||
#: lib/casserver/views.rb:101
|
||||
msgid "LOGIN"
|
||||
msgstr "登入"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
* {
|
||||
font-family: Verdana, sans-serif;
|
||||
font-family: Verdana, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -7,115 +7,115 @@ body {
|
|||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
input {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input.button {
|
||||
/*font-weight: bold;*/
|
||||
font-size: 10px;
|
||||
/*font-weight: bold;*/
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
#login-box {
|
||||
margin: 0 auto;
|
||||
width: 350px;
|
||||
top: 130px;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 350px;
|
||||
top: 130px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#headline-container {
|
||||
text-align: right;
|
||||
border-bottom: 1px solid #899989;
|
||||
font-family: Tahoma, Verdana, sans-serif;
|
||||
font-size: 22px;
|
||||
margin-right: 0px;
|
||||
padding-right: 7px;
|
||||
margin-left: 10px;
|
||||
letter-spacing: -0.25px;
|
||||
text-align: right;
|
||||
border-bottom: 1px solid #899989;
|
||||
font-family: Tahoma, Verdana, sans-serif;
|
||||
font-size: 22px;
|
||||
margin-right: 0px;
|
||||
padding-right: 7px;
|
||||
margin-left: 10px;
|
||||
letter-spacing: -0.25px;
|
||||
}
|
||||
|
||||
#logo-container {
|
||||
vertical-align: top;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#logo {
|
||||
}
|
||||
|
||||
#login-form-container {
|
||||
vertical-align: top;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
#username,
|
||||
#password {
|
||||
width: 10em;
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
#form-layout {
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#form-layout td {
|
||||
text-align: center;
|
||||
padding-bottom: 8px;
|
||||
text-align: center;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
#form-layout td#submit-container {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#infoline {
|
||||
font-size: 9px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
#messagebox-container {
|
||||
padding-left: 11px;
|
||||
padding-right: 16px;
|
||||
padding-left: 11px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
div.messagebox {
|
||||
font-size: 12px;
|
||||
padding: 5px;
|
||||
padding-left: 55px;
|
||||
text-align: center;
|
||||
width: 70%;
|
||||
min-height: 34px;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
padding: 5px;
|
||||
padding-left: 55px;
|
||||
text-align: center;
|
||||
width: 70%;
|
||||
min-height: 34px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.mistake {
|
||||
color: #d00;
|
||||
background-image: url(warning.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
color: #d00;
|
||||
background-image: url(warning.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.confirmation {
|
||||
color: #280;
|
||||
background-image: url(ok.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
color: #280;
|
||||
background-image: url(ok.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.notice {
|
||||
color: #04c;
|
||||
background-image: url(notice.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
color: #04c;
|
||||
background-image: url(notice.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
body {
|
||||
background-image: url(bg.png);
|
||||
background-image: url(bg.png);
|
||||
}
|
||||
|
||||
#headline-container {
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#login-box {
|
||||
margin: 0 auto;
|
||||
width: 450px;
|
||||
top: 110px;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 450px;
|
||||
top: 110px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
background-color: #fff;
|
||||
border: 1px #aaa solid;
|
||||
background-color: #fff;
|
||||
border: 1px #aaa solid;
|
||||
}
|
||||
|
||||
#logo-container {
|
||||
vertical-align: middle;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
body {
|
||||
background-image: url(bg.png);
|
||||
background-image: url(bg.png);
|
||||
}
|
||||
|
||||
label {
|
||||
color: #5c6156;
|
||||
color: #5c6156;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(login_box_bg.png);
|
||||
height: 175px;
|
||||
width: 210px;
|
||||
padding: 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(login_box_bg.png);
|
||||
height: 175px;
|
||||
width: 210px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#logo-container {
|
||||
vertical-align: top;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#logo {
|
||||
|
@ -24,10 +24,10 @@ label {
|
|||
}
|
||||
|
||||
#infoline {
|
||||
color: #5c6156;
|
||||
font-size: 8px;
|
||||
color: #5c6156;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
#headline-container {
|
||||
margin-right: 15px;
|
||||
}
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
|
8
setup.rb
8
setup.rb
|
@ -659,7 +659,7 @@ module FileOperations
|
|||
def ruby(*args)
|
||||
command config('rubyprog'), *args
|
||||
end
|
||||
|
||||
|
||||
def make(task = nil)
|
||||
command(*[config('makeprog'), task].compact)
|
||||
end
|
||||
|
@ -722,7 +722,7 @@ module HookScriptAPI
|
|||
def srcdirectory?(path)
|
||||
File.dir?(srcfile(path))
|
||||
end
|
||||
|
||||
|
||||
def srcfile?(path)
|
||||
File.file?(srcfile(path))
|
||||
end
|
||||
|
@ -826,7 +826,7 @@ class ToplevelInstaller
|
|||
__send__ "exec_#{task}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def run_metaconfigs
|
||||
@config.load_script "#{@ardir}/metaconfig"
|
||||
end
|
||||
|
@ -1404,7 +1404,7 @@ class Installer
|
|||
end
|
||||
|
||||
# picked up many entries from cvs-1.11.1/src/ignore.c
|
||||
JUNK_FILES = %w(
|
||||
JUNK_FILES = %w(
|
||||
core RCSLOG tags TAGS .make.state
|
||||
.nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
|
||||
*~ *.old *.bak *.BAK *.orig *.rej _$* *$
|
||||
|
|
|
@ -31,4 +31,4 @@ namespace :manifest do
|
|||
task :refresh do
|
||||
`rake check_manifest | patch -p0 > Manifest.txt`
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,5 +7,5 @@ end
|
|||
desc 'Creates mo files from po files and puts them to locale dir'
|
||||
task :mo do
|
||||
require 'gettext/utils'
|
||||
GetText.create_mofiles(true, "po", "locale")
|
||||
GetText.create_mofiles(true, "po", "locale")
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
* Add a C version of the ISAAC algorithm and make it possible to install
|
||||
the pure Ruby version and/or a version using a C extension for better
|
||||
performance.
|
||||
* Add a C version of the ISAAC algorithm and make it possible to install
|
||||
the pure Ruby version and/or a version using a C extension for better
|
||||
performance.
|
||||
|
|
|
@ -1,171 +1,171 @@
|
|||
module Crypt
|
||||
|
||||
# ISAAC is a fast, strong random number generator. Details on the
|
||||
# algorithm can be found here: http://burtleburtle.net/bob/rand/isaac.html
|
||||
# This provides a consistent and capable algorithm for producing
|
||||
# independent streams of quality random numbers.
|
||||
# ISAAC is a fast, strong random number generator. Details on the
|
||||
# algorithm can be found here: http://burtleburtle.net/bob/rand/isaac.html
|
||||
# This provides a consistent and capable algorithm for producing
|
||||
# independent streams of quality random numbers.
|
||||
|
||||
class ISAAC
|
||||
class ISAAC
|
||||
|
||||
attr_accessor :randrsl, :randcnt
|
||||
attr_accessor :mm, :aa, :bb, :cc
|
||||
attr_accessor :randrsl, :randcnt
|
||||
attr_accessor :mm, :aa, :bb, :cc
|
||||
|
||||
# When a Crypt::ISAAC object is created, it needs to be seeded for
|
||||
# random number generation. If the system has a /dev/urandom file,
|
||||
# that will be used to do the seeding by default. If false is explictly
|
||||
# passed when creating the object, it will instead use /dev/random to
|
||||
# generate its seeds. Be warned that this may make for SLOW
|
||||
# initialization.
|
||||
# If the requested source (/dev/urandom or /dev/random) do not exist,
|
||||
# the system will fall back to a simplistic initialization mechanism
|
||||
# using the builtin Mersenne Twister PRNG.
|
||||
# When a Crypt::ISAAC object is created, it needs to be seeded for
|
||||
# random number generation. If the system has a /dev/urandom file,
|
||||
# that will be used to do the seeding by default. If false is explictly
|
||||
# passed when creating the object, it will instead use /dev/random to
|
||||
# generate its seeds. Be warned that this may make for SLOW
|
||||
# initialization.
|
||||
# If the requested source (/dev/urandom or /dev/random) do not exist,
|
||||
# the system will fall back to a simplistic initialization mechanism
|
||||
# using the builtin Mersenne Twister PRNG.
|
||||
|
||||
def initialize(noblock = true)
|
||||
@mm = []
|
||||
@randrsl = []
|
||||
# Best initialization of the generator would be by pulling
|
||||
# numbers from /dev/random.
|
||||
rnd_source = noblock ? '/dev/urandom' : '/dev/random'
|
||||
if (FileTest.exist? rnd_source)
|
||||
File.open(rnd_source,'r') do |r|
|
||||
256.times do |t|
|
||||
z = r.read(4)
|
||||
x = z.unpack('V')[0]
|
||||
@randrsl[t] = x
|
||||
end
|
||||
end
|
||||
else
|
||||
# If urandom isn't available, the standard Ruby PRNG makes an
|
||||
# adequate fallback.
|
||||
256.times do |t|
|
||||
@randrsl[t] = Kernel.rand(4294967295)
|
||||
end
|
||||
end
|
||||
randinit(true)
|
||||
nil
|
||||
end
|
||||
def initialize(noblock = true)
|
||||
@mm = []
|
||||
@randrsl = []
|
||||
# Best initialization of the generator would be by pulling
|
||||
# numbers from /dev/random.
|
||||
rnd_source = noblock ? '/dev/urandom' : '/dev/random'
|
||||
if (FileTest.exist? rnd_source)
|
||||
File.open(rnd_source,'r') do |r|
|
||||
256.times do |t|
|
||||
z = r.read(4)
|
||||
x = z.unpack('V')[0]
|
||||
@randrsl[t] = x
|
||||
end
|
||||
end
|
||||
else
|
||||
# If urandom isn't available, the standard Ruby PRNG makes an
|
||||
# adequate fallback.
|
||||
256.times do |t|
|
||||
@randrsl[t] = Kernel.rand(4294967295)
|
||||
end
|
||||
end
|
||||
randinit(true)
|
||||
nil
|
||||
end
|
||||
|
||||
# Works just like the standard rand() function. If called with an
|
||||
# integer argument, rand() will return positive random number in
|
||||
# the range of 0 to (argument - 1). If called without an integer
|
||||
# argument, rand() returns a positive floating point number less than 1.
|
||||
|
||||
def rand(*num)
|
||||
if (@randcnt == 1)
|
||||
isaac
|
||||
@randcnt = 256
|
||||
end
|
||||
@randcnt -= 1
|
||||
if num[0].to_i > 0
|
||||
@randrsl[@randcnt].modulo(num[0])
|
||||
else
|
||||
".#{@randrsl[@randcnt]}".to_f
|
||||
end
|
||||
end
|
||||
# Works just like the standard rand() function. If called with an
|
||||
# integer argument, rand() will return positive random number in
|
||||
# the range of 0 to (argument - 1). If called without an integer
|
||||
# argument, rand() returns a positive floating point number less than 1.
|
||||
|
||||
def isaac
|
||||
i = 0
|
||||
x = 0
|
||||
y = 0
|
||||
def rand(*num)
|
||||
if (@randcnt == 1)
|
||||
isaac
|
||||
@randcnt = 256
|
||||
end
|
||||
@randcnt -= 1
|
||||
if num[0].to_i > 0
|
||||
@randrsl[@randcnt].modulo(num[0])
|
||||
else
|
||||
".#{@randrsl[@randcnt]}".to_f
|
||||
end
|
||||
end
|
||||
|
||||
@cc += 1
|
||||
@bb += @cc
|
||||
@bb & 0xffffffff
|
||||
def isaac
|
||||
i = 0
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
while (i < 256) do
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i + 128) & 255] + (@aa^(@aa << 13)) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
@cc += 1
|
||||
@bb += @cc
|
||||
@bb & 0xffffffff
|
||||
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i+128)&255] + (@aa^(0x03ffffff & (@aa >> 6))) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
while (i < 256) do
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i + 128) & 255] + (@aa^(@aa << 13)) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i + 128)&255] + (@aa^(@aa << 2)) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i+128)&255] + (@aa^(0x03ffffff & (@aa >> 6))) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i+128)&255] + (@aa^(0x0000ffff & (@aa >> 16))) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i + 128)&255] + (@aa^(@aa << 2)) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
|
||||
def randinit(flag)
|
||||
i = 0
|
||||
a = 0
|
||||
b = 0
|
||||
c = 0
|
||||
d = 0
|
||||
e = 0
|
||||
f = 0
|
||||
g = 0
|
||||
@aa = @bb = @cc = 0
|
||||
a = b = c = d = e = f = g = h = 0x9e3779b9
|
||||
x = @mm[i]
|
||||
@aa = (@mm[(i+128)&255] + (@aa^(0x0000ffff & (@aa >> 16))) ) & 0xffffffff
|
||||
@mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
|
||||
@randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
while (i < 4) do
|
||||
a ^= b<<1; d += a; b += c
|
||||
b ^= 0x3fffffff & (c>>2); e += b; c += d
|
||||
c ^= d << 8; f += c; d += e
|
||||
d ^= 0x0000ffff & (e >> 16); g += d; e += f
|
||||
e ^= f << 10; h += e; f += g
|
||||
f ^= 0x0fffffff & (g >> 4); a += f; g += h
|
||||
g ^= h << 8; b += g; h += a
|
||||
h ^= 0x007fffff & (a >> 9); c += h; a += b
|
||||
i += 1
|
||||
end
|
||||
def randinit(flag)
|
||||
i = 0
|
||||
a = 0
|
||||
b = 0
|
||||
c = 0
|
||||
d = 0
|
||||
e = 0
|
||||
f = 0
|
||||
g = 0
|
||||
@aa = @bb = @cc = 0
|
||||
a = b = c = d = e = f = g = h = 0x9e3779b9
|
||||
|
||||
i = 0
|
||||
while (i < 256) do
|
||||
if (flag)
|
||||
a+=@randrsl[i ].to_i; b+=@randrsl[i+1].to_i;
|
||||
c+=@randrsl[i+2]; d+=@randrsl[i+3];
|
||||
e+=@randrsl[i+4]; f+=@randrsl[i+5];
|
||||
g+=@randrsl[i+6]; h+=@randrsl[i+7];
|
||||
end
|
||||
while (i < 4) do
|
||||
a ^= b<<1; d += a; b += c
|
||||
b ^= 0x3fffffff & (c>>2); e += b; c += d
|
||||
c ^= d << 8; f += c; d += e
|
||||
d ^= 0x0000ffff & (e >> 16); g += d; e += f
|
||||
e ^= f << 10; h += e; f += g
|
||||
f ^= 0x0fffffff & (g >> 4); a += f; g += h
|
||||
g ^= h << 8; b += g; h += a
|
||||
h ^= 0x007fffff & (a >> 9); c += h; a += b
|
||||
i += 1
|
||||
end
|
||||
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=0x3fffffff & (c>>2); e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=0x0000ffff & (e>>16); g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=0x0fffffff & (g>>4); a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=0x007fffff & (a>>9); c+=h; a+=b;
|
||||
@mm[i]=a;@mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
|
||||
@mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
|
||||
i += 8
|
||||
end
|
||||
i = 0
|
||||
while (i < 256) do
|
||||
if (flag)
|
||||
a+=@randrsl[i ].to_i; b+=@randrsl[i+1].to_i;
|
||||
c+=@randrsl[i+2]; d+=@randrsl[i+3];
|
||||
e+=@randrsl[i+4]; f+=@randrsl[i+5];
|
||||
g+=@randrsl[i+6]; h+=@randrsl[i+7];
|
||||
end
|
||||
|
||||
if flag
|
||||
i = 0
|
||||
while (i < 256)
|
||||
a+=@mm[i ]; b+=@mm[i+1]; c+=@mm[i+2]; d+=@mm[i+3];
|
||||
e+=@mm[i+4]; f+=@mm[i+5]; g+=@mm[i+6]; h+=@mm[i+7];
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=0x3fffffff & (c>>2); e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=0x0000ffff & (e>>16); g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=0x0fffffff & (g>>4); a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=0x007fffff & (a>>9); c+=h; a+=b;
|
||||
@mm[i ]=a; @mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
|
||||
@mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
|
||||
i += 8
|
||||
end
|
||||
end
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=0x3fffffff & (c>>2); e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=0x0000ffff & (e>>16); g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=0x0fffffff & (g>>4); a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=0x007fffff & (a>>9); c+=h; a+=b;
|
||||
@mm[i]=a;@mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
|
||||
@mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
|
||||
i += 8
|
||||
end
|
||||
|
||||
isaac()
|
||||
@randcnt=256; # /* prepare to use the first set of results */
|
||||
end
|
||||
end
|
||||
if flag
|
||||
i = 0
|
||||
while (i < 256)
|
||||
a+=@mm[i ]; b+=@mm[i+1]; c+=@mm[i+2]; d+=@mm[i+3];
|
||||
e+=@mm[i+4]; f+=@mm[i+5]; g+=@mm[i+6]; h+=@mm[i+7];
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=0x3fffffff & (c>>2); e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=0x0000ffff & (e>>16); g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=0x0fffffff & (g>>4); a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=0x007fffff & (a>>9); c+=h; a+=b;
|
||||
@mm[i ]=a; @mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
|
||||
@mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
|
||||
i += 8
|
||||
end
|
||||
end
|
||||
|
||||
isaac()
|
||||
@randcnt=256; # /* prepare to use the first set of results */
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,9 +22,9 @@ KINDS = [
|
|||
|
||||
#{{{ list of files to be ignored stolen from setup.rb
|
||||
mapping = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' }
|
||||
ignore_files = %w[core RCSLOG tags TAGS .make.state .nse_depinfo
|
||||
ignore_files = %w[core RCSLOG tags TAGS .make.state .nse_depinfo
|
||||
#* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$
|
||||
*.org *.in .* ]
|
||||
*.org *.in .* ]
|
||||
#end of robbery
|
||||
IGNORE_FILES = ignore_files.map do |x|
|
||||
Regexp.new('\A' + x.gsub(/[\.\$\#\*]/){|c| mapping[c]} + '\z')
|
||||
|
@ -96,7 +96,7 @@ end
|
|||
|
||||
|
||||
module Actions
|
||||
|
||||
|
||||
class InstallFile
|
||||
|
||||
attr_reader :source, :destination, :mode
|
||||
|
@ -119,7 +119,7 @@ module Actions
|
|||
end
|
||||
|
||||
def eql?(other)
|
||||
self.class == other.class &&
|
||||
self.class == other.class &&
|
||||
@source == other.source &&
|
||||
@destination == other.destination &&
|
||||
@mode == other.mode
|
||||
|
@ -146,7 +146,7 @@ module Actions
|
|||
end
|
||||
|
||||
def <=>(other)
|
||||
FULL_ORDER[self, other] || self.directory <=> other.directory
|
||||
FULL_ORDER[self, other] || self.directory <=> other.directory
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -254,17 +254,17 @@ class PackageSpecification_1_0
|
|||
|
||||
def self.declare_file_type(args, &handle_arg)
|
||||
str_arr_p = lambda{|x| Array === x && x.all?{|y| String === y}}
|
||||
|
||||
|
||||
# strict type checking --- we don't want this to be extended arbitrarily
|
||||
unless args.size == 1 && Hash === args.first &&
|
||||
unless args.size == 1 && Hash === args.first &&
|
||||
args.first.all?{|f,r| [Proc, String, NilClass].include?(r.class) &&
|
||||
(String === f || str_arr_p[f])} or
|
||||
args.all?{|x| String === x || str_arr_p[x]}
|
||||
raise SpecificationError,
|
||||
raise SpecificationError,
|
||||
"Unspecified semantics for the given arguments: #{args.inspect}"
|
||||
end
|
||||
|
||||
if args.size == 1 && Hash === args.first
|
||||
if args.size == 1 && Hash === args.first
|
||||
args.first.to_a.each do |file, rename_info|
|
||||
if Array === file
|
||||
# ignoring boring files
|
||||
|
@ -284,7 +284,7 @@ class PackageSpecification_1_0
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#{{{ define the file tagging methods
|
||||
KINDS.each { |kind|
|
||||
define_method(kind) { |*args| # if this were 1.9 we could also take a block
|
||||
|
@ -330,7 +330,7 @@ class PackageSpecification_1_0
|
|||
target, options = @translate[kind][replaced_path]
|
||||
options ||= TRANSLATE_DEFAULT_OPTIONS
|
||||
if target && (replaced_path == dir || options[:inherit])
|
||||
dir = (target != '' ? File.join(target, *kept_dir_parts) :
|
||||
dir = (target != '' ? File.join(target, *kept_dir_parts) :
|
||||
File.join(*kept_dir_parts))
|
||||
break
|
||||
end
|
||||
|
@ -339,7 +339,7 @@ class PackageSpecification_1_0
|
|||
end
|
||||
dir
|
||||
end
|
||||
|
||||
|
||||
def add_file(kind, filename, new_filename_info, &callback)
|
||||
#TODO: refactor!!!
|
||||
if File.directory? filename #XXX setup.rb and rpa-base defined File.dir?
|
||||
|
@ -423,7 +423,7 @@ class PackageSpecification_1_0
|
|||
unless options.noop
|
||||
t = Test::Unit::AutoRunner.new(true)
|
||||
t.process_args(@unit_tests)
|
||||
t.run
|
||||
t.run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -445,7 +445,7 @@ class PackageSpecification_1_0
|
|||
key_val_pairs = additional_translations.to_a
|
||||
option_pairs = key_val_pairs.select{|(k,v)| Symbol === k}
|
||||
default_opts.update(Hash[*option_pairs.flatten])
|
||||
|
||||
|
||||
(key_val_pairs - option_pairs).each do |key, val|
|
||||
add_translation(kind, key, val, default_opts)
|
||||
end
|
||||
|
@ -486,7 +486,7 @@ class PackageSpecification_1_0
|
|||
opts.separator " setup compiles ruby extentions and others XXX"
|
||||
opts.separator " install installs files"
|
||||
opts.separator " test runs unit tests"
|
||||
|
||||
|
||||
|
||||
opts.separator ""
|
||||
opts.separator "Specific options:"
|
||||
|
@ -532,7 +532,7 @@ class PackageSpecification_1_0
|
|||
opts.on "--vendor", "install into distribution directories (for packagers)" do
|
||||
@dirs.update VENDOR_DIRS
|
||||
end
|
||||
|
||||
|
||||
opts.separator ""
|
||||
opts.separator "General options:"
|
||||
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
require 'test/unit'
|
||||
if ARGV[0] == 'local'
|
||||
begin
|
||||
require '../crypt/ISAAC.rb'
|
||||
rescue Exception
|
||||
require './crypt/ISAAC.rb'
|
||||
end
|
||||
begin
|
||||
require '../crypt/ISAAC.rb'
|
||||
rescue Exception
|
||||
require './crypt/ISAAC.rb'
|
||||
end
|
||||
else
|
||||
begin
|
||||
require 'crypt/ISAACC'
|
||||
rescue Exception
|
||||
require './crypt/ISAAC.rb'
|
||||
end
|
||||
begin
|
||||
require 'crypt/ISAACC'
|
||||
rescue Exception
|
||||
require './crypt/ISAAC.rb'
|
||||
end
|
||||
end
|
||||
|
||||
class TC_ISAAC < Test::Unit::TestCase
|
||||
def setup
|
||||
assert_nothing_raised("Failed to create a Crypt::ISAAC object.") do
|
||||
@generator = Crypt::ISAAC.new
|
||||
end
|
||||
end
|
||||
def setup
|
||||
assert_nothing_raised("Failed to create a Crypt::ISAAC object.") do
|
||||
@generator = Crypt::ISAAC.new
|
||||
end
|
||||
end
|
||||
|
||||
def testKind
|
||||
assert_kind_of(Crypt::ISAAC,@generator,"The created object is not a Crypt::ISAAC or subclass thereof.")
|
||||
end
|
||||
def testKind
|
||||
assert_kind_of(Crypt::ISAAC,@generator,"The created object is not a Crypt::ISAAC or subclass thereof.")
|
||||
end
|
||||
|
||||
def testInteger
|
||||
assert_nothing_raised("Failed while generating an integer random number.") do
|
||||
mynum = @generator.rand(1000000)
|
||||
assert_kind_of(Integer,mynum,"The generator failed to return an integer number in response to @generator.rand(1000000).")
|
||||
assert((mynum >= 0),"The generator returned a number that is less than 0 (#{mynum}).")
|
||||
assert((mynum < 1000000),"The generator returned a number that is greater than or equal to 1000000 (#{mynum}).")
|
||||
end
|
||||
end
|
||||
def testInteger
|
||||
assert_nothing_raised("Failed while generating an integer random number.") do
|
||||
mynum = @generator.rand(1000000)
|
||||
assert_kind_of(Integer,mynum,"The generator failed to return an integer number in response to @generator.rand(1000000).")
|
||||
assert((mynum >= 0),"The generator returned a number that is less than 0 (#{mynum}).")
|
||||
assert((mynum < 1000000),"The generator returned a number that is greater than or equal to 1000000 (#{mynum}).")
|
||||
end
|
||||
end
|
||||
|
||||
def testFloat
|
||||
assert_nothing_raised("Failed while generating a floating point random number.") do
|
||||
mynum = @generator.rand()
|
||||
assert_kind_of(Float,mynum,"The generator failed to return a floating point number in response to @generator.rand().")
|
||||
assert((mynum >= 0),"The generator returned a number that is less than 0 (#{mynum}).")
|
||||
assert((mynum < 1),"The generator returned a number that is greater than or equal to 1 (#{mynum}).")
|
||||
end
|
||||
end
|
||||
def testFloat
|
||||
assert_nothing_raised("Failed while generating a floating point random number.") do
|
||||
mynum = @generator.rand()
|
||||
assert_kind_of(Float,mynum,"The generator failed to return a floating point number in response to @generator.rand().")
|
||||
assert((mynum >= 0),"The generator returned a number that is less than 0 (#{mynum}).")
|
||||
assert((mynum < 1),"The generator returned a number that is greater than or equal to 1 (#{mynum}).")
|
||||
end
|
||||
end
|
||||
|
||||
def testIterations
|
||||
puts
|
||||
count = 0
|
||||
assert_nothing_raised("Failed on iteration #{count} while trying to generate 100000 random numbers.") do
|
||||
100000.times do
|
||||
count += 1
|
||||
x = @generator.rand(4294967295)
|
||||
print [x].pack('V').unpack('H8') if count % 1000 == 0
|
||||
if (count % 7000) == 0
|
||||
print "\n"
|
||||
else
|
||||
print " " if count % 1000 == 0
|
||||
end
|
||||
end
|
||||
puts "\n100000 numbers generated"
|
||||
end
|
||||
end
|
||||
def testIterations
|
||||
puts
|
||||
count = 0
|
||||
assert_nothing_raised("Failed on iteration #{count} while trying to generate 100000 random numbers.") do
|
||||
100000.times do
|
||||
count += 1
|
||||
x = @generator.rand(4294967295)
|
||||
print [x].pack('V').unpack('H8') if count % 1000 == 0
|
||||
if (count % 7000) == 0
|
||||
print "\n"
|
||||
else
|
||||
print " " if count % 1000 == 0
|
||||
end
|
||||
end
|
||||
puts "\n100000 numbers generated"
|
||||
end
|
||||
end
|
||||
|
||||
def testDualStreams
|
||||
g1 = nil
|
||||
g2 = nil
|
||||
assert_nothing_raised("Failed to pull numbers from two independent streams.") do
|
||||
g1 = Crypt::ISAAC.new
|
||||
g2 = Crypt::ISAAC.new
|
||||
assert((g1 != g2),"The generators are the same. This should not happen.")
|
||||
1000.times do
|
||||
g1.rand(4294967295)
|
||||
g2.rand(4294967295)
|
||||
end
|
||||
end
|
||||
end
|
||||
def testDualStreams
|
||||
g1 = nil
|
||||
g2 = nil
|
||||
assert_nothing_raised("Failed to pull numbers from two independent streams.") do
|
||||
g1 = Crypt::ISAAC.new
|
||||
g2 = Crypt::ISAAC.new
|
||||
assert((g1 != g2),"The generators are the same. This should not happen.")
|
||||
1000.times do
|
||||
g1.rand(4294967295)
|
||||
g2.rand(4294967295)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
h1. RubyCAS-Server
|
||||
|
||||
Please see "http://code.google.com/p/rubycas-server/":http://code.google.com/p/rubycas-server/ for more information.
|
||||
Please see "http://code.google.com/p/rubycas-server/":http://code.google.com/p/rubycas-server/ for more information.
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
* MA 02111-1307 USA *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
|
||||
var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()
|
||||
{ if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string")
|
||||
{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}
|
||||
|
|
|
@ -1,138 +1,138 @@
|
|||
body {
|
||||
background-color: #E1D1F1;
|
||||
font-family: "Georgia", sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.6em;
|
||||
padding: 1.6em 0 0 0;
|
||||
color: #333;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #444;
|
||||
}
|
||||
h1 {
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
margin: 5px;
|
||||
}
|
||||
li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: square;
|
||||
}
|
||||
a {
|
||||
color: #5E5AFF;
|
||||
background-color: #DAC;
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
}
|
||||
blockquote {
|
||||
font-size: 90%;
|
||||
font-style: italic;
|
||||
border-left: 1px solid #111;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.caps {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 45em;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.coda {
|
||||
text-align: right;
|
||||
color: #77f;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 90%;
|
||||
line-height: 1.4em;
|
||||
color: #ff8;
|
||||
background-color: #111;
|
||||
padding: 2px 10px 2px 10px;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
th {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: #0CC52B;
|
||||
}
|
||||
|
||||
.failed {
|
||||
color: #E90A1B;
|
||||
}
|
||||
|
||||
.unknown {
|
||||
color: #995000;
|
||||
}
|
||||
pre, code {
|
||||
font-family: monospace;
|
||||
font-size: 90%;
|
||||
line-height: 1.4em;
|
||||
color: #ff8;
|
||||
background-color: #111;
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
.comment { color: #aaa; font-style: italic; }
|
||||
.keyword { color: #eff; font-weight: bold; }
|
||||
.punct { color: #eee; font-weight: bold; }
|
||||
.symbol { color: #0bb; }
|
||||
.string { color: #6b4; }
|
||||
.ident { color: #ff8; }
|
||||
.constant { color: #66f; }
|
||||
.regex { color: #ec6; }
|
||||
.number { color: #F99; }
|
||||
.expr { color: #227; }
|
||||
|
||||
#version {
|
||||
float: right;
|
||||
text-align: right;
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
background-color: #B3ABFF;
|
||||
color: #141331;
|
||||
padding: 15px 20px 10px 20px;
|
||||
margin: 0 auto;
|
||||
margin-top: 15px;
|
||||
border: 3px solid #141331;
|
||||
}
|
||||
|
||||
#version .numbers {
|
||||
display: block;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#version p {
|
||||
text-decoration: none;
|
||||
color: #141331;
|
||||
background-color: #B3ABFF;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#version a {
|
||||
text-decoration: none;
|
||||
color: #141331;
|
||||
background-color: #B3ABFF;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #E1D1F1;
|
||||
font-family: "Georgia", sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.6em;
|
||||
padding: 1.6em 0 0 0;
|
||||
color: #333;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #444;
|
||||
}
|
||||
h1 {
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
margin: 5px;
|
||||
}
|
||||
li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: square;
|
||||
}
|
||||
a {
|
||||
color: #5E5AFF;
|
||||
background-color: #DAC;
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
}
|
||||
blockquote {
|
||||
font-size: 90%;
|
||||
font-style: italic;
|
||||
border-left: 1px solid #111;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.caps {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 45em;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.coda {
|
||||
text-align: right;
|
||||
color: #77f;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 90%;
|
||||
line-height: 1.4em;
|
||||
color: #ff8;
|
||||
background-color: #111;
|
||||
padding: 2px 10px 2px 10px;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
th {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: #0CC52B;
|
||||
}
|
||||
|
||||
.failed {
|
||||
color: #E90A1B;
|
||||
}
|
||||
|
||||
.unknown {
|
||||
color: #995000;
|
||||
}
|
||||
pre, code {
|
||||
font-family: monospace;
|
||||
font-size: 90%;
|
||||
line-height: 1.4em;
|
||||
color: #ff8;
|
||||
background-color: #111;
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
.comment { color: #aaa; font-style: italic; }
|
||||
.keyword { color: #eff; font-weight: bold; }
|
||||
.punct { color: #eee; font-weight: bold; }
|
||||
.symbol { color: #0bb; }
|
||||
.string { color: #6b4; }
|
||||
.ident { color: #ff8; }
|
||||
.constant { color: #66f; }
|
||||
.regex { color: #ec6; }
|
||||
.number { color: #F99; }
|
||||
.expr { color: #227; }
|
||||
|
||||
#version {
|
||||
float: right;
|
||||
text-align: right;
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
background-color: #B3ABFF;
|
||||
color: #141331;
|
||||
padding: 15px 20px 10px 20px;
|
||||
margin: 0 auto;
|
||||
margin-top: 15px;
|
||||
border: 3px solid #141331;
|
||||
}
|
||||
|
||||
#version .numbers {
|
||||
display: block;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#version p {
|
||||
text-decoration: none;
|
||||
color: #141331;
|
||||
background-color: #B3ABFF;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#version a {
|
||||
text-decoration: none;
|
||||
color: #141331;
|
||||
background-color: #B3ABFF;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче