Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 1 addition & 23 deletions app/controllers/api/reporting/one_time_tokens_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class API::Reporting::OneTimeTokensController < API::Reporting::BaseController
def authorize
@token = ReportingAPI::OneTimeToken.find_by!(token: params[:code])
@token.delete # <- Tokens are one-time use
json_data = { jwt: jwt(@token) }
json_data = { jwt: @token.to_jwt }
render json: json_data
rescue ActiveRecord::RecordNotFound
render json: { errors: "invalid_grant" }, status: :forbidden
Expand All @@ -23,26 +23,4 @@ def verify_grant_type!
return
end
end

def jwt_payload(token)
{
"iat" => Time.current.utc.to_i,
"data" => {
"user" => token.user.as_json,
"cis2_info" => token.cis2_info
}
}
end

def jwt(token)
JWT.encode(
jwt_payload(token),
Settings.reporting_api.client_app.secret,
"HS512"
)
end

def ensure_reporting_api_feature_enabled
render status: :forbidden and return unless Flipper.enabled?(:reporting_api)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def decode_jwt!(jwt)
jwt,
Settings.reporting_api.client_app.secret,
true,
{ algorithm: "HS512" }
{ algorithm: ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM }
)
end
end
Expand Down
20 changes: 20 additions & 0 deletions app/models/reporting_api/one_time_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class ReportingAPI::OneTimeToken < ApplicationRecord
validates :user_id, uniqueness: true, presence: true
validates :token, uniqueness: true, presence: true

JWT_SIGNING_ALGORITHM = "HS512"

def self.generate!(user_id:, cis2_info: {})
create!(user_id: user_id, token: SecureRandom.hex(32), cis2_info: cis2_info)
end
Expand All @@ -46,4 +48,22 @@ def self.find_or_generate_for!(user:, cis2_info: {})
def expired?
created_at < self.class.expire_before
end

def jwt_payload
{
"iat" => Time.current.utc.to_i,
"data" => {
"user" => user.as_json,
"cis2_info" => cis2_info
}
}
end

def to_jwt
JWT.encode(
jwt_payload,
Settings.reporting_api.client_app.secret,
JWT_SIGNING_ALGORITHM
)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@
response_json["jwt"],
Settings.reporting_api.client_app.secret,
true,
{ algorithm: "HS512" }
{
algorithm:
ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM
}
)
}.not_to raise_error
end
Expand All @@ -106,7 +109,10 @@
response_json["jwt"],
Settings.reporting_api.client_app.secret,
true,
{ algorithm: "HS512" }
{
algorithm:
ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM
}
)
end
let(:jwt_data) { decoded_payload.first["data"] }
Expand Down
6 changes: 3 additions & 3 deletions spec/controllers/api/reporting/totals_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
JWT.encode(
valid_payload,
Settings.reporting_api.client_app.secret,
"HS512"
ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM
)
end

Expand All @@ -58,7 +58,7 @@
JWT.encode(
valid_payload,
Settings.reporting_api.client_app.secret,
"HS512"
ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM
)
end

Expand All @@ -73,7 +73,7 @@
JWT.encode(
invalid_payload,
Settings.reporting_api.client_app.secret,
"HS512"
ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def current_user
jwt,
Settings.reporting_api.client_app.secret,
true,
{ algorithm: "HS512" }
{ algorithm: ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM }
) #.and_return(decoded_jwt)
an_object_which_includes_the_concern.send(:decode_jwt!, jwt)
end
Expand All @@ -284,7 +284,7 @@ def current_user
jwt,
Settings.reporting_api.client_app.secret,
true,
{ algorithm: "HS512" }
{ algorithm: ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM }
).and_return(decoded_jwt)
end

Expand Down
55 changes: 54 additions & 1 deletion spec/models/reporting_api/one_time_token_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#

describe ReportingAPI::OneTimeToken do
subject { described_class.new(user_id: user.id, token: SecureRandom.hex(32)) }
subject(:token) do
described_class.new(user_id: user.id, token: SecureRandom.hex(32))
end

let(:user) { create(:user) }

Expand Down Expand Up @@ -168,4 +170,55 @@
end
end
end

describe "#jwt_payload" do
let(:result) { token.jwt_payload }

it "has iat set to the current time as an integer" do
expect(result["iat"]).to be_within(1000).of(Time.current.utc.to_i)
end

it "has a data hash" do
expect(result["data"]).to be_a(Hash)
end

describe "the data hash" do
let(:data) { result["data"] }

it "has the user as json" do
expect(data["user"]).to eq(token.user.as_json)
end

it "has the cis2_info as json" do
expect(data["cis2_info"]).to eq(token.cis2_info.as_json)
end
end
end

describe "#to_jwt" do
let(:result) { token.to_jwt }
let(:decoded_payload) do
JWT.decode(
result,
Settings.reporting_api.client_app.secret,
true,
{ algorithm: ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM }
).first
end

it "returns a JWT signed with the Mavis reporting app secret" do
expect {
JWT.decode(
result,
Settings.reporting_api.client_app.secret,
true,
{ algorithm: ReportingAPI::OneTimeToken::JWT_SIGNING_ALGORITHM }
)
}.not_to raise_error
end

it "has the jwt_payload" do
expect(decoded_payload).to eq(token.jwt_payload)
end
end
end