Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to request a token from STS #16372

Merged
merged 8 commits into from
Apr 17, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ class ClaimsController < ApplicationController

def index
veis_token = client.request_veis_token
# Non-intuitive Ruby behavior: #split splits a string on space by default
vagov_token = request.headers['Authorization'].split[1]
btsss_token = client.request_btsss_token(veis_token, vagov_token)

sts_token = client.request_sts_token(@current_user)
btsss_token = client.request_btsss_token(veis_token, sts_token)

begin
claims = client.get_claims(veis_token, btsss_token)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ def ping
end

def authorized_ping
vagov_token = request.headers['Authorization'].split[1]
sts_token = client.request_sts_token(@current_user)
veis_token = client.request_veis_token
btsss_token = client.request_btsss_token(veis_token, vagov_token)
btsss_token = client.request_btsss_token(veis_token, sts_token)

btsss_authorized_ping_response = client.authorized_ping(veis_token, btsss_token)
render json: {
Expand Down
57 changes: 55 additions & 2 deletions modules/travel_pay/app/services/travel_pay/client.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'securerandom'

module TravelPay
class Client
##
Expand All @@ -24,7 +26,7 @@ def request_veis_token
#
# @return [Faraday::Response]
#
def request_btsss_token(veis_token, vagov_token)
def request_btsss_token(veis_token, sts_token)
btsss_url = Settings.travel_pay.base_url
api_key = Settings.travel_pay.subscription_key
client_number = Settings.travel_pay.client_number
Expand All @@ -33,7 +35,7 @@ def request_btsss_token(veis_token, vagov_token)
req.headers['Authorization'] = "Bearer #{veis_token}"
req.headers['Ocp-Apim-Subscription-Key'] = api_key
req.headers['BTSSS-API-Client-Number'] = client_number.to_s
req.body = { authJwt: vagov_token }
req.body = { authJwt: sts_token }
end
response.body['access_token']
end
Expand Down Expand Up @@ -90,8 +92,59 @@ def get_claims(veis_token, btsss_token)
symbolized_body[:data].sort_by(&parse_claim_date).reverse!
end

def request_sts_token(user)
host_baseurl = build_host_baseurl({ ip_form: false })
private_key_file = Settings.sign_in.sts_client.key_path
private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file))

assertion = build_sts_assertion(user)
jwt = JWT.encode(assertion, private_key, 'RS256')

# send to sis
response = connection(server_url: host_baseurl).post('/v0/sign_in/token') do |req|
req.params['grant_type'] = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
req.params['assertion'] = jwt
end

response.body['data']['access_token']
end

private

def build_sts_assertion(user)
service_account_id = Settings.travel_pay.sts.service_account_id
host_baseurl = build_host_baseurl({ ip_form: false })
audience_baseurl = build_host_baseurl({ ip_form: true })

current_time = Time.now.to_i
jti = SecureRandom.uuid

{
'iss' => host_baseurl,
'sub' => user.email,
'aud' => "#{audience_baseurl}/v0/sign_in/token",
'iat' => current_time,
'exp' => current_time + 300,
'scopes' => [],
'service_account_id' => service_account_id,
'jti' => jti,
'user_attributes' => { 'icn' => user.icn }
}
end

def build_host_baseurl(config)
env = Settings.vsp_environment
host = Settings.hostname

if env == 'localhost'
return 'http://127.0.0.1:3000' if config[:ip_form]

'http://localhost:3000'
end

"https://#{host}"
end

def veis_params
{
client_id: Settings.travel_pay.veis.client_id,
Expand Down
12 changes: 10 additions & 2 deletions modules/travel_pay/spec/controllers/claims_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
.to receive(:request_veis_token)
.and_return('veis_token')

allow_any_instance_of(TravelPay::Client)
.to receive(:request_sts_token)
.and_return('sts_token')

allow_any_instance_of(TravelPay::Client)
.to receive(:request_btsss_token)
.with('veis_token', 'vagov_token')
.with('veis_token', 'sts_token')
.and_return('btsss_token')

allow_any_instance_of(TravelPay::Client)
Expand All @@ -34,9 +38,13 @@
.to receive(:request_veis_token)
.and_return('veis_token')

allow_any_instance_of(TravelPay::Client)
.to receive(:request_sts_token)
.and_return('sts_token')

allow_any_instance_of(TravelPay::Client)
.to receive(:request_btsss_token)
.with('veis_token', 'vagov_token')
.with('veis_token', 'sts_token')
.and_return('btsss_token')

allow_any_instance_of(TravelPay::Client)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
before do
btsss_authorized_ping_response = double
allow(btsss_authorized_ping_response).to receive(:status).and_return(200)
allow(client)
.to receive(:request_sts_token)
.and_return('sample_sts_token')
allow(client)
.to receive(:request_btsss_token)
.and_return('sample_btsss_token')
Expand Down
Loading