diff --git a/lib/vmpooler/api/reroute.rb b/lib/vmpooler/api/reroute.rb index e318a19..4f574a3 100644 --- a/lib/vmpooler/api/reroute.rb +++ b/lib/vmpooler/api/reroute.rb @@ -15,6 +15,10 @@ module Vmpooler call env.merge("PATH_INFO" => "/api/v#{api_version}/summary/#{params[:route]}/#{params[:key]}") end + get '/token/?' do + call env.merge("PATH_INFO" => "/api/v#{api_version}/token") + end + post '/token/?' do call env.merge("PATH_INFO" => "/api/v#{api_version}/token") end diff --git a/lib/vmpooler/api/v1.rb b/lib/vmpooler/api/v1.rb index 5a6c757..12eaaff 100644 --- a/lib/vmpooler/api/v1.rb +++ b/lib/vmpooler/api/v1.rb @@ -162,6 +162,40 @@ module Vmpooler JSON.pretty_generate(result) end + get "#{api_prefix}/token/?" do + content_type :json + + status 404 + result = { 'ok' => false } + + if Vmpooler::API.settings.config[:auth] + status 401 + + need_auth! + + backend.keys('vmpooler__token__*').each do |key| + data = backend.hgetall(key) + + if data['user'] == Rack::Auth::Basic::Request.new(request.env).username + token = key.split('__').last + + result[token] ||= {} + result[token]['created'] = data['timestamp'] + + result['ok'] = true + end + end + + if result['ok'] + status 200 + else + status 404 + end + end + + JSON.pretty_generate(result) + end + get "#{api_prefix}/token/:token/?" do content_type :json diff --git a/spec/vmpooler/api/v1_spec.rb b/spec/vmpooler/api/v1_spec.rb index 1bdfa02..f85d712 100644 --- a/spec/vmpooler/api/v1_spec.rb +++ b/spec/vmpooler/api/v1_spec.rb @@ -27,6 +27,87 @@ describe Vmpooler::API::V1 do app.settings.set :redis, redis end + describe 'GET /token' do + context '(auth not configured)' do + let(:config) { { auth: false } } + + it 'returns a 404' do + get "#{prefix}/token" + + expect_json(ok = false, http = 404) + end + end + + context '(auth configured)' do + let(:config) { { auth: true } } + + it 'returns a 401 if not authed' do + get "#{prefix}/token" + + expect_json(ok = false, http = 401) + end + + it 'returns a list of tokens if authed' do + expect(redis).to receive(:keys).with('vmpooler__token__*').and_return(["vmpooler__token__abc"]) + expect(redis).to receive(:hgetall).with('vmpooler__token__abc').and_return({"user" => "admin", "timestamp" => "now"}) + + authorize 'admin', 's3cr3t' + + get "#{prefix}/token" + + expect(JSON.parse(last_response.body)['abc']['created']).to eq('now') + + expect_json(ok = true, http = 200) + end + end + end + + describe 'POST /token' do + context '(auth not configured)' do + let(:config) { { auth: false } } + + it 'returns a 404' do + post "#{prefix}/token" + + expect_json(ok = false, http = 404) + end + end + + context '(auth configured)' do + before do + allow(redis).to receive(:hset).and_return '1' + end + + let(:config) { { auth: true } } + + it 'returns a 401 if not authed' do + post "#{prefix}/token" + + expect_json(ok = false, http = 401) + end + + it 'returns a token if authed' do + authorize 'admin', 's3cr3t' + + post "#{prefix}/token" + + expect(JSON.parse(last_response.body)['token'].length).to be(32) + + expect_json(ok = true, http = 200) + end + end + end + end + + describe '/token/:token' do + let(:redis) { double('redis') } + let(:prefix) { '/api/v1' } + + before do + app.settings.set :config, config + app.settings.set :redis, redis + end + describe 'GET /token/:token' do context '(auth not configured)' do let(:config) { { auth: false } } @@ -63,42 +144,6 @@ describe Vmpooler::API::V1 do end end - describe 'POST /token' do - context '(auth not configured)' do - let(:config) { { auth: false } } - - it 'returns a 404' do - post "#{prefix}/token" - - expect_json(ok = false, http = 404) - end - end - - context '(auth configured)' do - before do - allow(redis).to receive(:hset).and_return '1' - end - - let(:config) { { auth: true } } - - it 'returns a 401 if not authed' do - post "#{prefix}/token" - - expect_json(ok = false, http = 401) - end - - it 'returns a token if authed' do - authorize 'admin', 's3cr3t' - - post "#{prefix}/token" - - expect(JSON.parse(last_response.body)['token'].length).to be(32) - - expect_json(ok = true, http = 200) - end - end - end - describe 'DELETE /token/:token' do context '(auth not configured)' do let(:config) { { auth: false } }