Skip to content

Commit 7f766a2

Browse files
committed
Validate global uniqueness of public keys.
1 parent f0884bd commit 7f766a2

38 files changed

+454
-13
lines changed

Diff for: app/helpers/gitolite_public_keys_helper.rb

+12
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,16 @@ def keylabel_text(key)
2121
"#{key.user.login}@#{key.title}"
2222
end
2323
end
24+
25+
def wrap_and_join(in_array,my_or="or")
26+
my_array = in_array.map{|x| "\"#{x}\""}
27+
length = my_array.length
28+
return my_array if length < 2
29+
my_array[length-1] = my_or+" "+my_array[length-1]
30+
if length == 2
31+
my_array.join(' ')
32+
else
33+
my_array.join(', ')
34+
end
35+
end
2436
end

Diff for: app/models/gitolite_public_key.rb

+118-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
require 'base64'
2+
include GitolitePublicKeysHelper
3+
14
class GitolitePublicKey < ActiveRecord::Base
25
STATUS_ACTIVE = 1
36
STATUS_LOCKED = 0
@@ -7,6 +10,10 @@ class GitolitePublicKey < ActiveRecord::Base
710

811
DEPLOY_PSEUDO_USER = "_deploy_key_"
912

13+
# These two constants are related -- don't change one without the other
14+
KEY_FORMATS = ['ssh-rsa', 'ssh-dss']
15+
KEY_NUM_COMPONENTS = [3,5]
16+
1017
belongs_to :user
1118
validates_uniqueness_of :title, :scope => :user_id
1219
validates_uniqueness_of :identifier, :scope => :user_id
@@ -23,18 +30,12 @@ def validate_associated_records_for_deployment_credentials() end
2330

2431
validate :has_not_been_changed
2532
validates_inclusion_of :key_type, :in => [KEY_TYPE_USER, KEY_TYPE_DEPLOY]
33+
validate :key_format_and_uniqueness
2634

2735
before_validation :set_identifier
36+
before_validation :strip_whitespace
2837
before_validation :remove_control_characters
2938

30-
def has_not_been_changed
31-
unless new_record?
32-
%w(identifier key user_id key_type).each do |attribute|
33-
errors.add(attribute, 'may not be changed') unless changes[attribute].blank?
34-
end
35-
end
36-
end
37-
3839
def set_identifier
3940
self.identifier ||=
4041
begin
@@ -81,11 +82,6 @@ def reset_identifier
8182
self.identifier
8283
end
8384

84-
# Remove control characters from key
85-
def remove_control_characters
86-
self.key=key.gsub(/[\a\r\n\t]/,'')
87-
end
88-
8985
def to_s ; title ; end
9086

9187
@@myregular = /^redmine_(.*)_\d*_\d*(.pub)?$/
@@ -97,4 +93,113 @@ def self.ident_to_user_token(identifier)
9793
def self.user_to_user_token(user)
9894
user.login.underscore.gsub(/[^0-9a-zA-Z\-]/,'_')
9995
end
96+
97+
protected
98+
99+
# Strip leading and trailing whitespace
100+
def strip_whitespace
101+
self.title = title.strip
102+
self.key = key.strip
103+
end
104+
105+
# Remove control characters from key
106+
def remove_control_characters
107+
# First -- let the first control char or space stand (to divide key type from key)
108+
# Really, this is catching a special case in which there is a \n between type and key.
109+
# Most common case turns first space back into space....
110+
self.key=key.sub(/[ \r\n\t]/,' ')
111+
112+
# Next, if comment divided from key by control char, let that one stand as well
113+
# We can only tell this if there is an "=" in the key. So, won't help 1/3 times.
114+
self.key=key.sub(/=[ \r\n\t]/,'= ')
115+
116+
# Delete any remaining control characters....
117+
self.key=key.gsub(/[\a\r\n\t]/,'').strip
118+
end
119+
120+
def has_not_been_changed
121+
unless new_record?
122+
%w(identifier key user_id key_type).each do |attribute|
123+
errors.add(attribute, 'may not be changed') unless changes[attribute].blank?
124+
end
125+
end
126+
end
127+
128+
def key_format_and_uniqueness
129+
return if key.blank? || !new_record?
130+
131+
# First, check that key crypto type is present and of correct form. Also, decode base64 and see if key
132+
# crypto type matches. Note that we ignore presence of comment!
133+
keypieces = key.match(/^(\S+)\s+(\S+)/)
134+
if !keypieces || keypieces[1].length > 10 # Probably has key as first component
135+
errors.add(:key,l(:error_key_needs_two_components))
136+
return
137+
end
138+
139+
if !(KEY_FORMATS.index(keypieces[1]))
140+
errors.add(:key,l(:error_key_bad_type,:types=>wrap_and_join(KEY_FORMATS,l(:word_or))))
141+
return
142+
end
143+
144+
# Make sure that key has proper number of characters (divisible by 4) and no more than 2 '='
145+
if (keypieces[2].length % 4) != 0 || !(keypieces[2].match(/^[a-zA-Z0-9\+\/]+={0,2}$/))
146+
Rails.logger.error "Key error: #{keypieces[2].length % 4}"
147+
errors.add(:key,l(:error_key_corrupted))
148+
return
149+
end
150+
151+
deckey = Base64.decode64(keypieces[2])
152+
piecearray=[]
153+
while deckey.length >= 4
154+
length = 0
155+
deckey.slice!(0..3).bytes do |byte|
156+
length = length * 256 + byte
157+
end
158+
if deckey.length < length
159+
errors.add(:key,l(:error_key_corrupted))
160+
return
161+
end
162+
piecearray << deckey.slice!(0..length-1)
163+
end
164+
if deckey.length != 0
165+
errors.add(:key,l(:error_key_corrupted))
166+
return
167+
end
168+
169+
if piecearray[0] != keypieces[1]
170+
errors.add(:key,l(:error_key_type_mismatch,:type1=>keypieces[1],:type2=>piecearray[0]))
171+
return
172+
end
173+
174+
if piecearray.length != KEY_NUM_COMPONENTS[KEY_FORMATS.index(piecearray[0])]
175+
errors.add(:key,l(:error_key_corrupted))
176+
return
177+
end
178+
179+
180+
# First version of uniqueness check -- simply check all keys...
181+
182+
# Check against the gitolite administrator key file (owned by noone).
183+
allkeys = [GitolitePublicKey.new({ :user=>nil, :key=>%x[cat '#{Setting.plugin_redmine_git_hosting['gitoliteIdentityPublicKeyFile']}'] })]
184+
# Check all active keys
185+
allkeys += (GitolitePublicKey.active.all)
186+
187+
allkeys.each do |existingkey|
188+
existingpieces = existingkey.key.match(/^(\S+)\s+(\S+)/)
189+
if existingpieces && (existingpieces[2] == keypieces[2])
190+
# Hm.... have a duplicate key!
191+
if existingkey.user == User.current
192+
errors.add(:key,l(:error_key_in_use_by_you,:name=>existingkey.title))
193+
elsif User.current.admin?
194+
if existingkey.user
195+
errors.add(:key,l(:error_key_in_use_by_other,:login=>existingkey.user.login,:name=>existingkey.title))
196+
else
197+
errors.add(:key,l(:error_key_in_use_by_admin))
198+
end
199+
else
200+
errors.add(:key,l(:error_key_in_use_by_someone))
201+
end
202+
end
203+
end
204+
end
100205
end

Diff for: config/locales/bg.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ bg:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/bs.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ bs:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/ca.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ ca:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/cs.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ cs:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/da.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ da:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/de.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ de:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/el.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ el:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/en.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ en:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/es.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ es:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/fi.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ fi:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/fr.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ fr:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/gl.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ gl:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

Diff for: config/locales/he.yml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ he:
8181
error_public_key_create_failed: Failed to create public key.
8282
error_public_key_update_failed: Failed to update public key.
8383
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can delete it and create a new one.'
84+
error_key_corrupted: seems to be corrupted.
85+
error_key_needs_two_components: 'needs at least two components: [key-type] and [key-value].'
86+
error_key_bad_type: 'has a bad type. Valid types are %{types}.'
87+
word_or: or
88+
error_key_type_mismatch: type (%{type1}) does not match type within body of key (%{type2}).
89+
error_key_in_use_by_you: 'is already in use by you as "%{name}".'
90+
error_key_in_use_by_other: 'is already in use by user "%{login}" as "%{name}".'
91+
error_key_in_use_by_admin: is already in use as the gitolite administrator key.
92+
error_key_in_use_by_someone: is already in use. It belongs to another user (ask administrator for details).
8493
activerecord:
8594
errors:
8695
messages:

0 commit comments

Comments
 (0)