-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathauth_controller.rb
More file actions
165 lines (140 loc) · 4.8 KB
/
auth_controller.rb
File metadata and controls
165 lines (140 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# encoding: ascii-8bit
# Copyright 2022 Ball Aerospace & Technologies Corp.
# All Rights Reserved.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See LICENSE.md for more details.
# Modified by OpenC3, Inc.
# All changes Copyright 2026, OpenC3, Inc.
# All Rights Reserved
#
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.
require 'openc3'
require 'openc3/models/auth_model'
class AuthController < ApplicationController
MAX_BAD_ATTEMPTS = ENV.fetch('OPENC3_AUTH_RATE_LIMIT_TO', '10').to_i
BAD_ATTEMPTS_WINDOW = ENV.fetch('OPENC3_AUTH_RATE_LIMIT_WITHIN', '120').to_i
@@user_bad_attempts_count = 0
@@user_bad_attempts_first_time = nil
@@user_bad_attempts_mutex = Mutex.new
@@service_bad_attempts_count = 0
@@service_bad_attempts_first_time = nil
@@service_bad_attempts_mutex = Mutex.new
def token_exists
result = OpenC3::AuthModel.set?
render json: {
result: result
}
end
def verify
if user_rate_limited?
head :too_many_requests
return
end
begin
if OpenC3::AuthModel.verify_no_service(params[:password], mode: :password)
render :plain => OpenC3::AuthModel.generate_session()
else
record_user_bad_attempt
head :unauthorized
end
rescue StandardError => e
log_error(e)
render json: { status: 'error', message: e.message, type: e.class }, status: 500
end
end
def verify_service
if service_rate_limited?
head :too_many_requests
return
end
begin
if OpenC3::AuthModel.verify(params[:password], service_only: true)
render :plain => OpenC3::AuthModel.generate_session()
else
record_service_bad_attempt
head :unauthorized
end
rescue StandardError => e
log_error(e)
render json: { status: 'error', message: e.message, type: e.class }, status: 500
end
end
def get_otp
user = authorization('system')
return unless user
render :plain => OpenC3::Authorization.generate_otp(user)
end
def set
if user_rate_limited?
head :too_many_requests
return
end
begin
# Set throws an exception if it fails for any reason
OpenC3::AuthModel.set(params[:password], params[:old_password])
OpenC3::Logger.info("Password changed", user: username())
render :plain => OpenC3::AuthModel.generate_session()
rescue StandardError => e
if e.message == "old_password incorrect"
record_user_bad_attempt
end
log_error(e)
render json: { status: 'error', message: e.message, type: e.class }, status: 500
end
end
private
# Checks to see if the user password has been rate limited due to bad attempts
def user_rate_limited?
@@user_bad_attempts_mutex.synchronize do
time = Time.now
# Reset counter if window has expired
if @@user_bad_attempts_first_time && (time - @@user_bad_attempts_first_time) > BAD_ATTEMPTS_WINDOW
@@user_bad_attempts_count = 0
@@user_bad_attempts_first_time = nil
end
return @@user_bad_attempts_count >= MAX_BAD_ATTEMPTS
end
end
# Initializes or increments the bad attempt counter for the user password
def record_user_bad_attempt
@@user_bad_attempts_mutex.synchronize do
time = Time.now
# Start new window if this is the first attempt or window expired
if @@user_bad_attempts_first_time.nil? || (time - @@user_bad_attempts_first_time) > BAD_ATTEMPTS_WINDOW
@@user_bad_attempts_count = 1
@@user_bad_attempts_first_time = time
else
@@user_bad_attempts_count += 1
end
end
end
# Checks to see if the service password has been rate limited due to bad attempts
def service_rate_limited?
@@service_bad_attempts_mutex.synchronize do
time = Time.now
# Reset counter if window has expired
if @@service_bad_attempts_first_time && (time - @@service_bad_attempts_first_time) > BAD_ATTEMPTS_WINDOW
@@service_bad_attempts_count = 0
@@service_bad_attempts_first_time = nil
end
return @@service_bad_attempts_count >= MAX_BAD_ATTEMPTS
end
end
# Initializes or increments the bad attempt counter for the service password
def record_service_bad_attempt
@@service_bad_attempts_mutex.synchronize do
time = Time.now
# Start new window if this is the first attempt or window expired
if @@service_bad_attempts_first_time.nil? || (time - @@service_bad_attempts_first_time) > BAD_ATTEMPTS_WINDOW
@@service_bad_attempts_count = 1
@@service_bad_attempts_first_time = time
else
@@service_bad_attempts_count += 1
end
end
end
end