Skip to content

Commit 47b605f

Browse files
committed
Disallow using session token to change password
1 parent 02086f8 commit 47b605f

File tree

3 files changed

+29
-22
lines changed

3 files changed

+29
-22
lines changed

openc3-cosmos-cmd-tlm-api/app/controllers/auth_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def verify
4444
end
4545

4646
begin
47-
if OpenC3::AuthModel.verify_no_service(params[:password], no_password: false)
47+
if OpenC3::AuthModel.verify_no_service(params[:password], mode: :password)
4848
render :plain => OpenC3::AuthModel.generate_session()
4949
else
5050
record_user_bad_attempt

openc3/lib/openc3/models/auth_model.rb

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,36 +58,43 @@ def self.verify(token, no_password: true, service_only: false)
5858

5959
return false if service_only
6060

61-
return verify_no_service(token, no_password: no_password)
61+
mode = no_password ? :token : :any
62+
return verify_no_service(token, mode: mode)
6263
end
6364

6465
# Checks whether the provided token is a valid user password or session token.
6566
# @param token [String] the plaintext password or session token to check (required)
66-
# @param no_password [Boolean] enforces use of a session token (default: true)
67+
# @param mode [String] optionally restrict verification to just the password or token. Valid values: :password, :token, or :any (default :token)
6768
# @return [Boolean] whether the provided password/token is valid
68-
def self.verify_no_service(token, no_password: true)
69+
def self.verify_no_service(token, mode: :token)
70+
modes = [:password, :token, :any]
71+
raise ArgumentError, "Invalid mode '#{mode}': must be one of #{modes}" unless modes.include?(mode)
72+
6973
return false if token.nil? or token.empty?
7074

7175
# Check cached session tokens and password hash
7276
time = Time.now
73-
return true if @@session_cache and (time - @@session_cache_time) < SESSION_CACHE_TIMEOUT and @@session_cache[token]
74-
unless no_password
75-
return true if @@pw_hash_cache and (time - @@pw_hash_cache_time) < PW_HASH_CACHE_TIMEOUT and Argon2::Password.verify_password(token, @@pw_hash_cache)
77+
unless mode == :password
78+
return true if @@session_cache and (time - @@session_cache_time) < SESSION_CACHE_TIMEOUT and @@session_cache[token]
79+
80+
# Check stored session tokens
81+
@@session_cache = Store.hgetall(SESSIONS_KEY)
82+
@@session_cache_time = time
83+
return true if @@session_cache[token]
7684
end
7785

78-
# Check stored session tokens
79-
@@session_cache = Store.hgetall(SESSIONS_KEY)
80-
@@session_cache_time = time
81-
return true if @@session_cache[token]
86+
unless mode == :token
87+
return true if @@pw_hash_cache and (time - @@pw_hash_cache_time) < PW_HASH_CACHE_TIMEOUT and Argon2::Password.verify_password(token, @@pw_hash_cache)
8288

83-
return false if no_password
89+
# Check stored password hash
90+
pw_hash = Store.get(PRIMARY_KEY)
91+
raise "invalid password hash" if pw_hash.nil? || !pw_hash.start_with?("$argon2") # Catch users who didn't run the migration utility when upgrading to COSMOS 7
92+
@@pw_hash_cache = pw_hash
93+
@@pw_hash_cache_time = time
94+
return true if Argon2::Password.verify_password(token, @@pw_hash_cache)
95+
end
8496

85-
# Check stored password hash
86-
pw_hash = Store.get(PRIMARY_KEY)
87-
raise "invalid password hash" if pw_hash.nil? || !pw_hash.start_with?("$argon2") # Catch users who didn't run the migration utility when upgrading to COSMOS 7
88-
@@pw_hash_cache = pw_hash
89-
@@pw_hash_cache_time = time
90-
return Argon2::Password.verify_password(token, @@pw_hash_cache)
97+
return false
9198
end
9299

93100
def self.set(password, old_password, key = PRIMARY_KEY)
@@ -96,7 +103,7 @@ def self.set(password, old_password, key = PRIMARY_KEY)
96103

97104
if set?(key)
98105
raise "old_password must not be nil or empty" if old_password.nil? or old_password.empty?
99-
raise "old_password incorrect" unless verify_no_service(old_password, no_password: false)
106+
raise "old_password incorrect" unless verify_no_service(old_password, mode: :password)
100107
end
101108
pw_hash = Argon2::Password.create(password, profile: ARGON2_PROFILE)
102109
Store.set(key, pw_hash)

openc3/spec/models/auth_model_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ module OpenC3
4343
raise_error(/old_password incorrect/)
4444

4545
AuthModel.set('newpassword', AUTH_INITIAL_PASSWORD)
46-
expect(AuthModel.verify_no_service(AUTH_INITIAL_PASSWORD, no_password: false)).to eq(false)
47-
expect(AuthModel.verify_no_service('newpassword', no_password: false)).to eq(true)
46+
expect(AuthModel.verify_no_service(AUTH_INITIAL_PASSWORD, mode: :any)).to eq(false)
47+
expect(AuthModel.verify_no_service('newpassword', mode: :any)).to eq(true)
4848
end
4949

5050
it "self.verify" do
@@ -63,7 +63,7 @@ module OpenC3
6363

6464
it "raises when stored password hash is SHA256" do
6565
@redis.set(PW_HASH_PRIMARY_KEY, Digest::SHA256.hexdigest(AUTH_INITIAL_PASSWORD))
66-
expect{ AuthModel.verify_no_service(AUTH_INITIAL_PASSWORD, no_password: false) }.to \
66+
expect{ AuthModel.verify_no_service(AUTH_INITIAL_PASSWORD, mode: :any) }.to \
6767
raise_error(/invalid password hash/)
6868
end
6969
end

0 commit comments

Comments
 (0)