gunark-rubycas-server 0.8.0.20090715 → 0.8.0.20090812

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,7 @@
15
15
  * Failure to connect to a service during a single sign out request is now
16
16
  handled gracefully.
17
17
  * Required gem dependencies have been re-enabled in the gemspec.
18
+ * Authlogic authenticator files added to gemspec. [rajiv]
18
19
 
19
20
  === 0.7.1 :: 2008-11-10
20
21
 
data/Rakefile CHANGED
@@ -1,4 +1,115 @@
1
1
  require 'config/requirements'
2
2
  require 'config/hoe' # setup Hoe + all gem configuration
3
3
 
4
- Dir['tasks/**/*.rake'].each { |rake| load rake }
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
6
+ desc "generate a self signed SSL certificate (in order to get going easily)"
7
+ task :generate_ssl_certificate do
8
+ `mkdir -p ssl/newcerts ssl/private`
9
+ File.open("ssl/openssl.cnf", "w") do |f|
10
+ f.write <<-EOF
11
+ #
12
+ # OpenSSL configuration file.
13
+ #
14
+
15
+ # Establish working directory.
16
+
17
+ dir = .
18
+
19
+ [ ca ]
20
+ default_ca = CA_default
21
+
22
+ [ CA_default ]
23
+ serial = $dir/serial
24
+ database = $dir/index.txt
25
+ new_certs_dir = $dir/newcerts
26
+ certificate = $dir/cacert.pem
27
+ private_key = $dir/private/cakey.pem
28
+ default_days = 365
29
+ default_md = md5
30
+ preserve = no
31
+ email_in_dn = no
32
+ nameopt = default_ca
33
+ certopt = default_ca
34
+ policy = policy_match
35
+
36
+ [ policy_match ]
37
+ countryName = match
38
+ stateOrProvinceName = match
39
+ organizationName = match
40
+ organizationalUnitName = optional
41
+ commonName = supplied
42
+ emailAddress = optional
43
+
44
+ [ req ]
45
+ default_bits = 1024 # Size of keys
46
+ default_keyfile = key.pem # name of generated keys
47
+ default_md = md5 # message digest algorithm
48
+ string_mask = nombstr # permitted characters
49
+ distinguished_name = req_distinguished_name
50
+ req_extensions = v3_req
51
+
52
+ [ req_distinguished_name ]
53
+ # Variable name Prompt string
54
+ #---------------------- ----------------------------------
55
+ 0.organizationName = Organization Name (company)
56
+ organizationalUnitName = Organizational Unit Name (department, division)
57
+ emailAddress = Email Address
58
+ emailAddress_max = 40
59
+ localityName = Locality Name (city, district)
60
+ stateOrProvinceName = State or Province Name (full name)
61
+ countryName = Country Name (2 letter code)
62
+ countryName_min = 2
63
+ countryName_max = 2
64
+ commonName = Common Name (hostname, IP, or your name)
65
+ commonName_max = 64
66
+
67
+ # Default values for the above, for consistency and less typing.
68
+ # Variable name Value
69
+ #------------------------------ ------------------------------
70
+ 0.organizationName_default = The Sample Company
71
+ localityName_default = Metropolis
72
+ stateOrProvinceName_default = New York
73
+ countryName_default = US
74
+ commonName_default = localhost
75
+
76
+ [ v3_ca ]
77
+ basicConstraints = CA:TRUE
78
+ subjectKeyIdentifier = hash
79
+ authorityKeyIdentifier = keyid:always,issuer:always
80
+
81
+ [ v3_req ]
82
+ basicConstraints = CA:FALSE
83
+ subjectKeyIdentifier = hash
84
+ EOF
85
+ end
86
+
87
+ `cd ssl && echo '01' > serial`
88
+ `cd ssl && touch index.txt`
89
+
90
+ puts
91
+ puts "When asked for a passphrase enter one, for example rubycas"
92
+ puts
93
+
94
+ `cd ssl && openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf`
95
+ `cd ssl && openssl req -new -nodes -out req.pem -config ./openssl.cnf`
96
+ `cd ssl && openssl ca -out cert.pem -config ./openssl.cnf -infiles req.pem`
97
+
98
+
99
+
100
+
101
+ puts
102
+ puts "If you are using Firefox and want to access the CAS server through localhost you need to add an exception:"
103
+ puts " 1. Go to Preferences > Advanced > Encryption > View Certificates"
104
+ puts " 2. Click the Tab Servers"
105
+ puts " 3. Click the Button Add Exception"
106
+ puts " 4. Enter https://localhost:<port> into the textfield and press Get Certificate"
107
+ puts " 5. Then press View"
108
+ puts " 6. Then press Confirm Security Exception"
109
+
110
+ end
111
+
112
+ desc "clear all generated files for SSL certificate"
113
+ task :clear_ssl_certificate do
114
+ `rm -rf ssl`
115
+ end
@@ -32,10 +32,17 @@ server: webrick
32
32
  port: 443
33
33
  ssl_cert: /path/to/your/ssl.pem
34
34
 
35
- # If your private key is separate from cert
35
+ # If your private key is in a separate file from the cert
36
36
 
37
37
  #ssl_key: /path/to/your/private_key.pem
38
38
 
39
+ # If you do not already have an SSL certificate and would like to automatically
40
+ # generate one, run the "generate_ssl_certificate" rake task and use the following
41
+ # settings:
42
+
43
+ # ssl_cert: ssl/cert.pem
44
+ # ssl_key: ssl/key.pem
45
+
39
46
 
40
47
  # By default the login page will be available at the root path
41
48
  # (e.g. https://login.example.net/). The uri_path option lets you serve it from a
@@ -0,0 +1,43 @@
1
+ require "openssl"
2
+
3
+ module Authlogic
4
+ module CryptoProviders
5
+ # This encryption method is reversible if you have the supplied key. So in order to use this encryption method you must supply it with a key first.
6
+ # In an initializer, or before your application initializes, you should do the following:
7
+ #
8
+ # Authlogic::CryptoProviders::AES256.key = "my really long and unique key, preferrably a bunch of random characters"
9
+ #
10
+ # My final comment is that this is a strong encryption method, but its main weakness is that its reversible. If you do not need to reverse the hash
11
+ # then you should consider Sha512 or BCrypt instead.
12
+ #
13
+ # Keep your key in a safe place, some even say the key should be stored on a separate server.
14
+ # This won't hurt performance because the only time it will try and access the key on the separate server is during initialization, which only
15
+ # happens once. The reasoning behind this is if someone does compromise your server they won't have the key also. Basically, you don't want to
16
+ # store the key with the lock.
17
+ class AES256
18
+ class << self
19
+ attr_writer :key
20
+
21
+ def encrypt(*tokens)
22
+ aes.encrypt
23
+ aes.key = @key
24
+ [aes.update(tokens.join) + aes.final].pack("m").chomp
25
+ end
26
+
27
+ def matches?(crypted, *tokens)
28
+ aes.decrypt
29
+ aes.key = @key
30
+ (aes.update(crypted.unpack("m").first) + aes.final) == tokens.join
31
+ rescue OpenSSL::CipherError
32
+ false
33
+ end
34
+
35
+ private
36
+ def aes
37
+ raise ArgumentError.new("You must provide a key like #{name}.key = my_key before using the #{name}") if @key.blank?
38
+ @aes ||= OpenSSL::Cipher::Cipher.new("AES-256-ECB")
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,92 @@
1
+ begin
2
+ require "bcrypt"
3
+ rescue LoadError
4
+ end
5
+
6
+ module Authlogic
7
+ module CryptoProviders
8
+ # For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear launch codes you might want to consier BCrypt. This is an extremely
9
+ # secure hashing algorithm, mainly because it is slow. A brute force attack on a BCrypt encrypted password would take much longer than a brute force attack on a
10
+ # password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this, generating a password takes exponentially longer than any
11
+ # of the Sha algorithms. I did some benchmarking to save you some time with your decision:
12
+ #
13
+ # require "bcrypt"
14
+ # require "digest"
15
+ # require "benchmark"
16
+ #
17
+ # Benchmark.bm(18) do |x|
18
+ # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
19
+ # x.report("BCrypt (cost = 2:") { 100.times { BCrypt::Password.create("mypass", :cost => 2) } }
20
+ # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
21
+ # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
22
+ # end
23
+ #
24
+ # user system total real
25
+ # BCrypt (cost = 10): 10.780000 0.060000 10.840000 ( 11.100289)
26
+ # BCrypt (cost = 2): 0.180000 0.000000 0.180000 ( 0.181914)
27
+ # Sha512: 0.000000 0.000000 0.000000 ( 0.000829)
28
+ # Sha1: 0.000000 0.000000 0.000000 ( 0.000395)
29
+ #
30
+ # You can play around with the cost to get that perfect balance between performance and security.
31
+ #
32
+ # Decided BCrypt is for you? Just insall the bcrypt gem:
33
+ #
34
+ # gem install bcrypt-ruby
35
+ #
36
+ # Tell acts_as_authentic to use it:
37
+ #
38
+ # acts_as_authentic do |c|
39
+ # c.crypto_provider = Authlogic::CryptoProviders::BCrypt
40
+ # end
41
+ #
42
+ # You are good to go!
43
+ class BCrypt
44
+ class << self
45
+ # This is the :cost option for the BCrpyt library. The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10.
46
+ # Set this to whatever you want, play around with it to get that perfect balance between security and performance.
47
+ def cost
48
+ @cost ||= 10
49
+ end
50
+ attr_writer :cost
51
+
52
+ # Creates a BCrypt hash for the password passed.
53
+ def encrypt(*tokens)
54
+ ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
55
+ end
56
+
57
+ # Does the hash match the tokens? Uses the same tokens that were used to encrypt.
58
+ def matches?(hash, *tokens)
59
+ $LOG.debug hash
60
+ $LOG.debug tokens.inspect
61
+
62
+ hash = new_from_hash(hash)
63
+ return false if hash.blank?
64
+ hash == join_tokens(tokens)
65
+ end
66
+
67
+ # This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost
68
+ def cost_matches?(hash)
69
+ hash = new_from_hash(hash)
70
+ if hash.blank?
71
+ false
72
+ else
73
+ hash.cost == cost
74
+ end
75
+ end
76
+
77
+ private
78
+ def join_tokens(tokens)
79
+ tokens.flatten.join
80
+ end
81
+
82
+ def new_from_hash(hash)
83
+ begin
84
+ ::BCrypt::Password.new(hash)
85
+ rescue ::BCrypt::Errors::InvalidHash
86
+ return nil
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,34 @@
1
+ require "digest/md5"
2
+
3
+ module Authlogic
4
+ module CryptoProviders
5
+ # This class was made for the users transitioning from md5 based systems.
6
+ # I highly discourage using this crypto provider as it superbly inferior
7
+ # to your other options.
8
+ #
9
+ # Please use any other provider offered by Authlogic.
10
+ class MD5
11
+ class << self
12
+ attr_accessor :join_token
13
+
14
+ # The number of times to loop through the encryption.
15
+ def stretches
16
+ @stretches ||= 1
17
+ end
18
+ attr_writer :stretches
19
+
20
+ # Turns your raw password into a MD5 hash.
21
+ def encrypt(*tokens)
22
+ digest = tokens.flatten.join(join_token)
23
+ stretches.times { digest = Digest::MD5.hexdigest(digest) }
24
+ digest
25
+ end
26
+
27
+ # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
28
+ def matches?(crypted, *tokens)
29
+ encrypt(*tokens) == crypted
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ require "digest/sha1"
2
+
3
+ module Authlogic
4
+ module CryptoProviders
5
+ # This class was made for the users transitioning from restful_authentication. I highly discourage using this
6
+ # crypto provider as it inferior to your other options. Please use any other provider offered by Authlogic.
7
+ class Sha1
8
+ class << self
9
+ def join_token
10
+ @join_token ||= "--"
11
+ end
12
+ attr_writer :join_token
13
+
14
+ # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
15
+ def stretches
16
+ @stretches ||= 10
17
+ end
18
+ attr_writer :stretches
19
+
20
+ # Turns your raw password into a Sha1 hash.
21
+ def encrypt(*tokens)
22
+ tokens = tokens.flatten
23
+ digest = tokens.shift
24
+ stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token)) }
25
+ digest
26
+ end
27
+
28
+ # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
29
+ def matches?(crypted, *tokens)
30
+ encrypt(*tokens) == crypted
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ require "digest/sha2"
2
+
3
+ module Authlogic
4
+ # The acts_as_authentic method has a crypto_provider option. This allows you to use any type of encryption you like.
5
+ # Just create a class with a class level encrypt and matches? method. See example below.
6
+ #
7
+ # === Example
8
+ #
9
+ # class MyAwesomeEncryptionMethod
10
+ # def self.encrypt(*tokens)
11
+ # # the tokens passed will be an array of objects, what type of object is irrelevant,
12
+ # # just do what you need to do with them and return a single encrypted string.
13
+ # # for example, you will most likely join all of the objects into a single string and then encrypt that string
14
+ # end
15
+ #
16
+ # def self.matches?(crypted, *tokens)
17
+ # # return true if the crypted string matches the tokens.
18
+ # # depending on your algorithm you might decrypt the string then compare it to the token, or you might
19
+ # # encrypt the tokens and make sure it matches the crypted string, its up to you
20
+ # end
21
+ # end
22
+ module CryptoProviders
23
+ # = Sha512
24
+ #
25
+ # Uses the Sha512 hash algorithm to encrypt passwords.
26
+ class Sha512
27
+ class << self
28
+ attr_accessor :join_token
29
+
30
+ # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
31
+ def stretches
32
+ @stretches ||= 20
33
+ end
34
+ attr_writer :stretches
35
+
36
+ # Turns your raw password into a Sha512 hash.
37
+ def encrypt(*tokens)
38
+ digest = tokens.flatten.join(join_token)
39
+ stretches.times { digest = Digest::SHA512.hexdigest(digest) }
40
+ digest
41
+ end
42
+
43
+ # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
44
+ def matches?(crypted, *tokens)
45
+ encrypt(*tokens) == crypted
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,97 @@
1
+ require 'casserver/authenticators/base'
2
+
3
+ # These were pulled directly from Authlogic, and new ones can be added
4
+ # just by including new Crypto Providers
5
+ require File.dirname(__FILE__) + '/authlogic_crypto_providers/aes256'
6
+ require File.dirname(__FILE__) + '/authlogic_crypto_providers/bcrypt'
7
+ require File.dirname(__FILE__) + '/authlogic_crypto_providers/md5'
8
+ require File.dirname(__FILE__) + '/authlogic_crypto_providers/sha1'
9
+ require File.dirname(__FILE__) + '/authlogic_crypto_providers/sha512'
10
+
11
+ begin
12
+ require 'active_record'
13
+ rescue LoadError
14
+ require 'rubygems'
15
+ require 'active_record'
16
+ end
17
+
18
+ # This is a version of the SQL authenticator that works nicely with Authlogic.
19
+ # Passwords are encrypted the same way as it done in Authlogic.
20
+ # Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
21
+ # config.
22
+ #
23
+ # Using this authenticator requires restful authentication plugin on rails (client) side.
24
+ #
25
+ # * git://github.com/binarylogic/authlogic.git
26
+ #
27
+ # Usage:
28
+
29
+ # authenticator:
30
+ # class: CASServer::Authenticators::SQLAuthlogic
31
+ # database:
32
+ # adapter: mysql
33
+ # database: some_database_with_users_table
34
+ # user: root
35
+ # password:
36
+ # server: localhost
37
+ # user_table: user
38
+ # username_column: login
39
+ # password_column: crypted_password
40
+ # salt_column: password_salt
41
+ # encryptor: BCrypt
42
+ #
43
+ class CASServer::Authenticators::SQLAuthlogic < CASServer::Authenticators::Base
44
+
45
+ def validate(credentials)
46
+ read_standard_credentials(credentials)
47
+
48
+ raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
49
+ raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless @options[:database]
50
+
51
+ CASUser.establish_connection @options[:database]
52
+ CASUser.set_table_name @options[:user_table] || "users"
53
+
54
+ username_column = @options[:username_column] || "login"
55
+ password_column = @options[:password_column] || "crypted_password"
56
+ salt_column = @options[:salt_column]
57
+ results = CASUser.find(:all, :conditions => ["#{username_column} = ?", @username])
58
+
59
+ begin
60
+ encryptor = eval("Authlogic::CryptoProviders::" + @options[:encryptor] || "Sha512")
61
+ rescue
62
+ encryptor = Authlogic::CryptoProviders::Sha512
63
+ end
64
+
65
+ if results.size > 0
66
+ $LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
67
+ user = results.first
68
+ tokens = [@password, (not salt_column.nil?) && user.send(salt_column) || nil].compact
69
+ crypted = user.send(password_column)
70
+
71
+ unless @options[:extra_attributes].blank?
72
+ if results.size > 1
73
+ $LOG.warn("#{self.class}: Unable to extract extra_attributes because multiple matches were found for #{@username.inspect}")
74
+ else
75
+
76
+ @extra_attributes = {}
77
+ extra_attributes_to_extract.each do |col|
78
+ @extra_attributes[col] = user.send(col)
79
+ end
80
+
81
+ if @extra_attributes.empty?
82
+ $LOG.warn("#{self.class}: Did not read any extra_attributes for user #{@username.inspect} even though an :extra_attributes option was provided.")
83
+ else
84
+ $LOG.debug("#{self.class}: Read the following extra_attributes for user #{@username.inspect}: #{@extra_attributes.inspect}")
85
+ end
86
+ end
87
+ end
88
+
89
+ return encryptor.matches?(crypted, tokens)
90
+ else
91
+ return false
92
+ end
93
+ end
94
+
95
+ class CASUser < ActiveRecord::Base
96
+ end
97
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gunark-rubycas-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.20090715
4
+ version: 0.8.0.20090812
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Zukowski
@@ -94,6 +94,11 @@ files:
94
94
  - custom_views.example.rb
95
95
  - lib/casserver.rb
96
96
  - lib/casserver/authenticators/active_directory_ldap.rb
97
+ - lib/casserver/authenticators/authlogic_crypto_providers/aes256.rb
98
+ - lib/casserver/authenticators/authlogic_crypto_providers/bcrypt.rb
99
+ - lib/casserver/authenticators/authlogic_crypto_providers/md5.rb
100
+ - lib/casserver/authenticators/authlogic_crypto_providers/sha1.rb
101
+ - lib/casserver/authenticators/authlogic_crypto_providers/sha512.rb
97
102
  - lib/casserver/authenticators/base.rb
98
103
  - lib/casserver/authenticators/client_certificate.rb
99
104
  - lib/casserver/authenticators/google.rb
@@ -101,6 +106,7 @@ files:
101
106
  - lib/casserver/authenticators/ntlm.rb
102
107
  - lib/casserver/authenticators/open_id.rb
103
108
  - lib/casserver/authenticators/sql.rb
109
+ - lib/casserver/authenticators/sql_authlogic.rb
104
110
  - lib/casserver/authenticators/sql_encrypted.rb
105
111
  - lib/casserver/authenticators/sql_md5.rb
106
112
  - lib/casserver/authenticators/sql_rest_auth.rb
@@ -157,6 +163,7 @@ files:
157
163
  - vendor/isaac_0.9.1/test/TC_ISAAC.rb
158
164
  has_rdoc: true
159
165
  homepage: http://rubycas-server.rubyforge.org
166
+ licenses:
160
167
  post_install_message: |+
161
168
 
162
169
  For more information on RubyCAS-Server, see http://code.google.com/p/rubycas-server
@@ -185,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
192
  requirements: []
186
193
 
187
194
  rubyforge_project: rubycas-server
188
- rubygems_version: 1.2.0
195
+ rubygems_version: 1.3.5
189
196
  signing_key:
190
197
  specification_version: 2
191
198
  summary: Provides single sign-on authentication for web applications using the CAS protocol.