Skip to content

Commit 1a69e2f

Browse files
authored
fix(authentication): return errors detail instead of generic error 500 (#636)
1 parent 92657b8 commit 1a69e2f

File tree

4 files changed

+83
-35
lines changed

4 files changed

+83
-35
lines changed

app/controllers/forest_liana/authentication_controller.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ def start_authentication
3939
end
4040

4141
def authentication_callback
42+
return authentication_exception if params.key?(:error)
43+
4244
begin
4345
token = @authentication_service.verify_code_and_generate_token(params)
4446

@@ -55,6 +57,21 @@ def authentication_callback
5557
end
5658
end
5759

60+
def authentication_exception
61+
begin
62+
raise ForestLiana::Errors::AuthenticationOpenIdClientException.new(params[:error], params[:error_description], params[:state])
63+
rescue => error
64+
FOREST_REPORTER.report error
65+
FOREST_LOGGER.error "AuthenticationOpenIdClientException: #{error.error_description}"
66+
67+
render json: {
68+
error: error.error,
69+
error_description: error.error_description,
70+
state: error.state
71+
}, status: :unauthorized
72+
end
73+
end
74+
5875
def logout
5976
begin
6077
if cookies.has_key?(:forest_session_token)

app/services/forest_liana/authentication.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ def parse_state(state)
3838
raise ForestLiana::MESSAGES[:SERVER_TRANSACTION][:INVALID_STATE_MISSING]
3939
end
4040

41-
rendering_id = nil
42-
4341
begin
4442
parsed_state = JSON.parse(state.gsub("'",'"').gsub('=>',':'))
4543
rendering_id = parsed_state["renderingId"].to_s

config/initializers/errors.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ def initialize(action_name=nil, field_name=nil, hook_name=nil)
3030
end
3131
end
3232

33+
class AuthenticationOpenIdClientException < StandardError
34+
attr_reader :error, :error_description, :state
35+
36+
def initialize(error, error_description, state)
37+
super(error_description)
38+
@error = error
39+
@error_description = error_description
40+
@state = state
41+
end
42+
end
43+
3344
class ExpectedError < StandardError
3445
attr_reader :error_code, :status, :message, :name
3546

spec/requests/authentications_spec.rb

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,44 +44,66 @@
4444
end
4545

4646
describe "GET /authentication/callback" do
47-
before() do
48-
response = '{"data":{"id":666,"attributes":{"first_name":"Alice","last_name":"Doe","email":"[email protected]","teams":[1,2,3],"role":"Test","tags":[{"key":"city","value":"Paris"}]}}}'
49-
allow(ForestLiana::ForestApiRequester).to receive(:get).with(
50-
"/liana/v2/renderings/42/authorization", { :headers => { "forest-token" => "THE-ACCESS-TOKEN" }, :query => {} }
51-
).and_return(
52-
instance_double(HTTParty::Response, :body => response, :code => 200)
53-
)
54-
55-
get ForestLiana::Engine.routes.url_helpers.authentication_callback_path + "?code=THE-CODE&state=#{CGI::escape('{"renderingId":42}')}"
56-
end
47+
context 'when the response is a 200' do
48+
before() do
49+
response = '{"data":{"id":666,"attributes":{"first_name":"Alice","last_name":"Doe","email":"[email protected]","teams":[1,2,3],"role":"Test","tags":[{"key":"city","value":"Paris"}]}}}'
50+
allow(ForestLiana::ForestApiRequester).to receive(:get).with(
51+
"/liana/v2/renderings/42/authorization", { :headers => { "forest-token" => "THE-ACCESS-TOKEN" }, :query => {} }
52+
).and_return(
53+
instance_double(HTTParty::Response, :body => response, :code => 200)
54+
)
5755

58-
it "should respond with a 200 code" do
59-
expect(response).to have_http_status(200)
60-
end
56+
get ForestLiana::Engine.routes.url_helpers.authentication_callback_path + "?code=THE-CODE&state=#{CGI::escape('{"renderingId":42}')}"
57+
end
6158

62-
it "should return a valid authentication token" do
63-
body = JSON.parse(response.body, :symbolize_names => true);
59+
it "should respond with a 200 code" do
60+
expect(response).to have_http_status(200)
61+
end
6462

65-
token = body[:token]
66-
decoded = JWT.decode(token, ForestLiana.auth_secret, true, { algorithm: 'HS256' })[0]
63+
it "should return a valid authentication token" do
64+
body = JSON.parse(response.body, :symbolize_names => true);
6765

68-
expected_token_data = {
69-
"id" => 666,
70-
"email" => '[email protected]',
71-
"rendering_id" => "42",
72-
"first_name" => 'Alice',
73-
"last_name" => 'Doe',
74-
"team" => 1,
75-
"role" => "Test",
76-
}
66+
token = body[:token]
67+
decoded = JWT.decode(token, ForestLiana.auth_secret, true, { algorithm: 'HS256' })[0]
7768

78-
expect(decoded).to include(expected_token_data)
79-
tags = decoded['tags']
80-
expect(tags.length).to eq(1)
81-
expect(tags[0]['key']).to eq("city")
82-
expect(tags[0]['value']).to eq("Paris")
83-
expect(body).to eq({ token: token, tokenData: decoded.deep_symbolize_keys! })
84-
expect(response).to have_http_status(200)
69+
expected_token_data = {
70+
"id" => 666,
71+
"email" => '[email protected]',
72+
"rendering_id" => "42",
73+
"first_name" => 'Alice',
74+
"last_name" => 'Doe',
75+
"team" => 1,
76+
"role" => "Test",
77+
}
78+
79+
expect(decoded).to include(expected_token_data)
80+
tags = decoded['tags']
81+
expect(tags.length).to eq(1)
82+
expect(tags[0]['key']).to eq("city")
83+
expect(tags[0]['value']).to eq("Paris")
84+
expect(body).to eq({ token: token, tokenData: decoded.deep_symbolize_keys! })
85+
expect(response).to have_http_status(200)
86+
end
87+
end
88+
89+
context 'when the response is not a 200' do
90+
before() do
91+
get ForestLiana::Engine.routes.url_helpers.authentication_callback_path,
92+
params: {
93+
error: 'TrialBlockedError',
94+
error_description: 'Your free trial has ended. We hope you enjoyed your experience with Forest Admin.',
95+
state: '{"renderingId":100}'
96+
},
97+
headers: {
98+
'Accept' => 'application/json',
99+
'Content-Type' => 'application/json',
100+
}
101+
end
102+
103+
it "should respond with a 401 code" do
104+
expect(response).to have_http_status(401)
105+
expect(response.body).to eq('{"error":"TrialBlockedError","error_description":"Your free trial has ended. We hope you enjoyed your experience with Forest Admin.","state":"{\"renderingId\":100}"}')
106+
end
85107
end
86108
end
87109

0 commit comments

Comments
 (0)