##// END OF EJS Templates
Merged r7985 from trunk....
Jean-Philippe Lang -
r7877:5d1388db02a2
parent child
Show More
@@ -1,95 +1,95
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module Redmine
19 19 module Ciphering
20 20 def self.included(base)
21 21 base.extend ClassMethods
22 22 end
23 23
24 24 class << self
25 25 def encrypt_text(text)
26 if cipher_key.blank?
26 if cipher_key.blank? || text.blank?
27 27 text
28 28 else
29 29 c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
30 30 iv = c.random_iv
31 31 c.encrypt
32 32 c.key = cipher_key
33 33 c.iv = iv
34 34 e = c.update(text.to_s)
35 35 e << c.final
36 36 "aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
37 37 end
38 38 end
39 39
40 40 def decrypt_text(text)
41 41 if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/)
42 42 text = match[1]
43 43 c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
44 44 e, iv = text.split("--").map {|s| Base64.decode64(s)}
45 45 c.decrypt
46 46 c.key = cipher_key
47 47 c.iv = iv
48 48 d = c.update(e)
49 49 d << c.final
50 50 else
51 51 text
52 52 end
53 53 end
54 54
55 55 def cipher_key
56 56 key = Redmine::Configuration['database_cipher_key'].to_s
57 57 key.blank? ? nil : Digest::SHA256.hexdigest(key)
58 58 end
59 59 end
60 60
61 61 module ClassMethods
62 62 def encrypt_all(attribute)
63 63 transaction do
64 64 all.each do |object|
65 65 clear = object.send(attribute)
66 66 object.send "#{attribute}=", clear
67 67 raise(ActiveRecord::Rollback) unless object.save(false)
68 68 end
69 69 end ? true : false
70 70 end
71 71
72 72 def decrypt_all(attribute)
73 73 transaction do
74 74 all.each do |object|
75 75 clear = object.send(attribute)
76 76 object.write_attribute attribute, clear
77 77 raise(ActiveRecord::Rollback) unless object.save(false)
78 78 end
79 79 end
80 80 end ? true : false
81 81 end
82 82
83 83 private
84 84
85 85 # Returns the value of the given ciphered attribute
86 86 def read_ciphered_attribute(attribute)
87 87 Redmine::Ciphering.decrypt_text(read_attribute(attribute))
88 88 end
89 89
90 90 # Sets the value of the given ciphered attribute
91 91 def write_ciphered_attribute(attribute, value)
92 92 write_attribute(attribute, Redmine::Ciphering.encrypt_text(value))
93 93 end
94 94 end
95 95 end
@@ -1,84 +1,92
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../../test_helper', __FILE__)
19 19
20 20 class Redmine::CipheringTest < ActiveSupport::TestCase
21 21
22 22 def test_password_should_be_encrypted
23 23 Redmine::Configuration.with 'database_cipher_key' => 'secret' do
24 24 r = Repository::Subversion.generate!(:password => 'foo')
25 25 assert_equal 'foo', r.password
26 26 assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/)
27 27 end
28 28 end
29 29
30 30 def test_password_should_be_clear_with_blank_key
31 31 Redmine::Configuration.with 'database_cipher_key' => '' do
32 32 r = Repository::Subversion.generate!(:password => 'foo')
33 33 assert_equal 'foo', r.password
34 34 assert_equal 'foo', r.read_attribute(:password)
35 35 end
36 36 end
37 37
38 38 def test_password_should_be_clear_with_nil_key
39 39 Redmine::Configuration.with 'database_cipher_key' => nil do
40 40 r = Repository::Subversion.generate!(:password => 'foo')
41 41 assert_equal 'foo', r.password
42 42 assert_equal 'foo', r.read_attribute(:password)
43 43 end
44 44 end
45 45
46 def test_blank_password_should_be_clear
47 Redmine::Configuration.with 'database_cipher_key' => 'secret' do
48 r = Repository::Subversion.generate!(:password => '')
49 assert_equal '', r.password
50 assert_equal '', r.read_attribute(:password)
51 end
52 end
53
46 54 def test_unciphered_password_should_be_readable
47 55 Redmine::Configuration.with 'database_cipher_key' => nil do
48 56 r = Repository::Subversion.generate!(:password => 'clear')
49 57 end
50 58
51 59 Redmine::Configuration.with 'database_cipher_key' => 'secret' do
52 60 r = Repository.first(:order => 'id DESC')
53 61 assert_equal 'clear', r.password
54 62 end
55 63 end
56 64
57 65 def test_encrypt_all
58 66 Repository.delete_all
59 67 Redmine::Configuration.with 'database_cipher_key' => nil do
60 68 Repository::Subversion.generate!(:password => 'foo')
61 69 Repository::Subversion.generate!(:password => 'bar')
62 70 end
63 71
64 72 Redmine::Configuration.with 'database_cipher_key' => 'secret' do
65 73 assert Repository.encrypt_all(:password)
66 74 r = Repository.first(:order => 'id DESC')
67 75 assert_equal 'bar', r.password
68 76 assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/)
69 77 end
70 78 end
71 79
72 80 def test_decrypt_all
73 81 Repository.delete_all
74 82 Redmine::Configuration.with 'database_cipher_key' => 'secret' do
75 83 Repository::Subversion.generate!(:password => 'foo')
76 84 Repository::Subversion.generate!(:password => 'bar')
77 85
78 86 assert Repository.decrypt_all(:password)
79 87 r = Repository.first(:order => 'id DESC')
80 88 assert_equal 'bar', r.password
81 89 assert_equal 'bar', r.read_attribute(:password)
82 90 end
83 91 end
84 92 end
General Comments 0
You need to be logged in to leave comments. Login now