summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2016-03-28 15:55:19 -0700
committerelijah <elijah@riseup.net>2016-03-28 16:03:54 -0700
commite072ac2fa8bc93ed782df1ff95130f4794f9640f (patch)
tree986c2cfd607af3f6c0e9c34f62d82de07ff0f3f6
parent67b5aa4198e0f6ab2cd29767aedcb4bf5b5dc4d9 (diff)
api: added allow ability to limit what IPs can access api using a static configured auth token.
-rw-r--r--app/controllers/controller_extension/token_authentication.rb2
-rw-r--r--app/models/api_token.rb27
-rw-r--r--config/routes.rb3
-rw-r--r--test/functional/v1/identities_controller_test.rb20
-rw-r--r--test/functional/v1/users_controller_test.rb52
-rw-r--r--test/support/auth_test_helper.rb15
6 files changed, 109 insertions, 10 deletions
diff --git a/app/controllers/controller_extension/token_authentication.rb b/app/controllers/controller_extension/token_authentication.rb
index 15ddef7..c41d61b 100644
--- a/app/controllers/controller_extension/token_authentication.rb
+++ b/app/controllers/controller_extension/token_authentication.rb
@@ -5,7 +5,7 @@ module ControllerExtension::TokenAuthentication
def token
@token ||= authenticate_with_http_token do |token, options|
- Token.find_by_token(token) || ApiToken.find_by_token(token)
+ Token.find_by_token(token) || ApiToken.find_by_token(token, request.headers['REMOTE_ADDR'])
end
end
diff --git a/app/models/api_token.rb b/app/models/api_token.rb
index 49b1870..5c7923d 100644
--- a/app/models/api_token.rb
+++ b/app/models/api_token.rb
@@ -14,10 +14,12 @@ class ApiToken
# Searches static config to see if there is a matching api token string.
# Return an ApiToken if successful, or nil otherwise.
#
- def self.find_by_token(token)
+ def self.find_by_token(token, ip_address=nil)
if APP_CONFIG["api_tokens"].nil? || APP_CONFIG["api_tokens"].empty?
# no api auth tokens are configured
return nil
+ elsif ip_address && !ip_allowed?(ip_address)
+ return nil
elsif !token.is_a?(String) || token.size < 24
# don't allow obviously invalid token strings
return nil
@@ -25,8 +27,8 @@ class ApiToken
token_digest = Digest::SHA512.hexdigest(token)
username = self.static_auth_tokens[token_digest]
if username
- if username == "test"
- return ApiTestToken.new
+ if username == "monitor"
+ return ApiMonitorToken.new
elsif username == "admin"
# not yet supported
return nil
@@ -51,14 +53,25 @@ class ApiToken
#
def self.static_auth_tokens
@static_auth_tokens ||= APP_CONFIG["api_tokens"].inject({}) {|hsh, entry|
- hsh[Digest::SHA512.hexdigest(entry[1])] = entry[0]
+ if ["monitor", "admin"].include?(entry[0])
+ hsh[Digest::SHA512.hexdigest(entry[1])] = entry[0]
+ end
hsh
}.freeze
end
+ def self.ip_allowed?(ip)
+ ip == "0.0.0.0" ||
+ ip == "127.0.0.1" || (
+ APP_CONFIG["api_tokens"] &&
+ APP_CONFIG["api_tokens"]["allowed_ips"].is_a?(Array) &&
+ APP_CONFIG["api_tokens"]["allowed_ips"].include?(ip)
+ )
+ end
+
end
-class ApiAdminToken < Token
+class ApiAdminToken < ApiToken
# not yet supported
#def authenticate
# AdminUser.new
@@ -69,8 +82,8 @@ end
# These tokens used by the platform to run regular monitor tests
# of a production infrastructure.
#
-class ApiTestToken < Token
+class ApiMonitorToken < ApiToken
def authenticate
- ApiTestUser.new
+ ApiMonitorUser.new
end
end
diff --git a/config/routes.rb b/config/routes.rb
index da6edce..c455dd7 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -30,12 +30,13 @@ LeapWeb::Application.routes.draw do
resources :sessions, :only => [:new, :create, :update],
:constraints => { :id => /[^\/]+(?=\.json\z)|[^\/]+/ }
delete "logout" => "sessions#destroy", :as => "logout"
- resources :users, :only => [:create, :update, :destroy, :index]
+ resources :users, :only => [:create, :update, :destroy, :index, :show]
resources :messages, :only => [:index, :update]
resource :cert, :only => [:show, :create]
resource :smtp_cert, :only => [:create]
resource :service, :only => [:show]
resources :configs, :only => [:index, :show]
+ resources :identities, :only => [:show]
end
scope "(:locale)", :locale => CommonLanguages.match_available do
diff --git a/test/functional/v1/identities_controller_test.rb b/test/functional/v1/identities_controller_test.rb
new file mode 100644
index 0000000..3e88402
--- /dev/null
+++ b/test/functional/v1/identities_controller_test.rb
@@ -0,0 +1,20 @@
+require_relative '../../test_helper'
+
+class V1::IdentitiesControllerTest < ActionController::TestCase
+
+ test "api monitor can fetch identity" do
+ monitor_auth do
+ identity = FactoryGirl.create :identity
+ get :show, :id => identity.address, :format => 'json'
+ assert_response :success
+ assert_equal identity, assigns(:identity)
+ end
+ end
+
+ test "anonymous cannot fetch identity" do
+ identity = FactoryGirl.create :identity
+ get :show, :id => identity.address, :format => 'json'
+ assert_response :forbidden
+ end
+
+end
diff --git a/test/functional/v1/users_controller_test.rb b/test/functional/v1/users_controller_test.rb
index ffe2484..7afbb02 100644
--- a/test/functional/v1/users_controller_test.rb
+++ b/test/functional/v1/users_controller_test.rb
@@ -1,4 +1,4 @@
-require 'test_helper'
+require_relative '../../test_helper'
class V1::UsersControllerTest < ActionController::TestCase
@@ -81,4 +81,54 @@ class V1::UsersControllerTest < ActionController::TestCase
end
end
+ test "admin can show user" do
+ user = FactoryGirl.create :user
+ login :is_admin? => true
+ get :show, :id => 0, :login => user.login, :format => :json
+ assert_response :success
+ assert_json_response user
+ get :show, :id => user.id, :format => :json
+ assert_response :success
+ assert_json_response user
+ get :show, :id => "0", :format => :json
+ assert_response :not_found
+ end
+
+ test "normal users cannot show user" do
+ user = find_record :user
+ login
+ get :show, :id => 0, :login => user.login, :format => :json
+ assert_access_denied
+ end
+
+ test "api monitor auth can create and destroy test users" do
+ with_config(allow_registration: false) do
+ monitor_auth do
+ user_attribs = record_attributes_for :test_user
+ post :create, :user => user_attribs, :format => :json
+ assert_response :success
+ delete :destroy, :id => assigns(:user).id, :format => :json
+ assert_response :success
+ end
+ end
+ end
+
+ test "api monitor auth cannot create normal users" do
+ monitor_auth do
+ user_attribs = record_attributes_for :user
+ post :create, :user => user_attribs, :format => :json
+ assert_response :forbidden
+ end
+ end
+
+ test "api monitor auth cannot delete normal users" do
+ post :create, :user => record_attributes_for(:user), :format => :json
+ assert_response :success
+ normal_user_id = assigns(:user).id
+ monitor_auth do
+ delete :destroy, :id => normal_user_id, :format => :json
+ assert_response :forbidden
+ end
+ end
+
end
diff --git a/test/support/auth_test_helper.rb b/test/support/auth_test_helper.rb
index 7af3341..acc6076 100644
--- a/test/support/auth_test_helper.rb
+++ b/test/support/auth_test_helper.rb
@@ -29,6 +29,21 @@ module AuthTestHelper
@token.expects(:destroy) if @token
end
+ # authenticate as the api monitor
+ def monitor_auth(&block)
+ token_auth(APP_CONFIG['api_tokens']['monitor'], &block)
+ end
+
+ # authenticate with a token
+ def token_auth(token_str)
+ original = request.env['HTTP_AUTHORIZATION']
+ request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials(token_str)
+ if block_given?
+ yield
+ request.env['HTTP_AUTHORIZATION'] = original
+ end
+ end
+
protected
def header_for_token_auth