From 9a8577a2d19aa51318dce6ff9ffe1bd26f25c09e Mon Sep 17 00:00:00 2001
From: elijah <elijah@riseup.net>
Date: Mon, 28 Mar 2016 15:56:21 -0700
Subject: api: added get(:show) to identities and users, allow monitors to
 create/delete test & tmp users.

---
 .../controller_extension/authentication.rb         |  6 +++
 app/controllers/v1/identities_controller.rb        | 12 +++++
 app/controllers/v1/users_controller.rb             | 51 ++++++++++++++++++----
 app/models/user.rb                                 |  6 ++-
 test/functional/token_auth_test.rb                 | 40 +++++++++++++++++
 test/integration/api/signup_test.rb                |  4 +-
 6 files changed, 107 insertions(+), 12 deletions(-)
 create mode 100644 app/controllers/v1/identities_controller.rb
 create mode 100644 test/functional/token_auth_test.rb

diff --git a/app/controllers/controller_extension/authentication.rb b/app/controllers/controller_extension/authentication.rb
index e2b24f0..63b9e5f 100644
--- a/app/controllers/controller_extension/authentication.rb
+++ b/app/controllers/controller_extension/authentication.rb
@@ -34,6 +34,12 @@ module ControllerExtension::Authentication
     access_denied unless admin?
   end
 
+  def require_monitor
+    unless current_user.is_monitor? || current_user.is_admin?
+      access_denied
+    end
+  end
+
   def authentication_errors
     return unless attempted_login?
     errors = get_warden_errors
diff --git a/app/controllers/v1/identities_controller.rb b/app/controllers/v1/identities_controller.rb
new file mode 100644
index 0000000..1d8c542
--- /dev/null
+++ b/app/controllers/v1/identities_controller.rb
@@ -0,0 +1,12 @@
+module V1
+  class IdentitiesController < ApiController
+    before_filter :token_authenticate
+    before_filter :require_monitor
+
+    def show
+      @identity = Identity.find_by_address(params[:id])
+      respond_with @identity
+    end
+
+  end
+end
diff --git a/app/controllers/v1/users_controller.rb b/app/controllers/v1/users_controller.rb
index 2e840d9..8296eb0 100644
--- a/app/controllers/v1/users_controller.rb
+++ b/app/controllers/v1/users_controller.rb
@@ -2,10 +2,12 @@ module V1
   class UsersController < ApiController
     include ControllerExtension::FetchUser
 
+    # allow optional access to this controller using API auth tokens:
+    before_filter :token_authenticate
+
     before_filter :fetch_user, :only => [:update, :destroy]
-    before_filter :require_admin, :only => [:index]
+    before_filter :require_monitor, :only => [:index, :show]
     before_filter :require_login, :only => [:index, :update, :destroy]
-    before_filter :require_registration_allowed, only: :create
 
     respond_to :json
 
@@ -19,9 +21,27 @@ module V1
       end
     end
 
+    def show
+      if params[:login]
+        @user = User.find_by_login(params[:login])
+      elsif params[:id]
+        @user = User.find(params[:id])
+      end
+      if @user
+        respond_with @user
+      else
+        not_found
+      end
+    end
+
     def create
-      @user = Account.create(params[:user])
-      respond_with @user # return ID instead?
+      if current_user.is_monitor?
+        create_test_account
+      elsif APP_CONFIG[:allow_registration]
+        create_account
+      else
+        head :forbidden
+      end
     end
 
     def update
@@ -30,19 +50,34 @@ module V1
     end
 
     def destroy
-      @user.account.destroy(params[:identities] == "destroy")
+      destroy_identity = current_user.is_monitor? || params[:identities] == "destroy"
+      @user.account.destroy(destroy_identity)
       if @user == current_user
         logout
       end
       render :json => {'success' => 'user deleted'}
     end
 
-    protected
+    private
+
+    # tester auth can only create test users.
+    def create_test_account
+      if User::is_test?(params[:user][:login])
+        @user = Account.create(params[:user])
+        respond_with @user
+      else
+        head :forbidden
+      end
+    end
 
-    def require_registration_allowed
-      unless APP_CONFIG[:allow_registration]
+    def create_account
+      if APP_CONFIG[:allow_registration]
+        @user = Account.create(params[:user])
+        respond_with @user # return ID instead?
+      else
         head :forbidden
       end
     end
+
   end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 1c54f0c..51e9279 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -68,8 +68,10 @@ class User < CouchRest::Model::Base
 
   def to_json(options={})
     {
-      :login => login,
-      :ok => valid?
+      :login => self.login,
+      :ok => self.valid?,
+      :id => self.id,
+      :enabled => self.enabled?
     }.to_json(options)
   end
 
diff --git a/test/functional/token_auth_test.rb b/test/functional/token_auth_test.rb
new file mode 100644
index 0000000..53d5fb3
--- /dev/null
+++ b/test/functional/token_auth_test.rb
@@ -0,0 +1,40 @@
+#
+# tests for authenticating an admin or monitor user
+# via static configured tokens.
+#
+
+require_relative '../test_helper'
+
+class TokenAuthTest < ActionController::TestCase
+  tests V1::ConfigsController
+
+  def test_login_via_api_token
+    with_config(:allow_anonymous_certs => false) do
+      monitor_auth do
+        get :index
+        assert assigns(:token), 'should have authenticated via api token'
+        assert assigns(:token).is_a? ApiToken
+        assert @controller.send(:current_user).is_a? ApiMonitorUser
+      end
+    end
+  end
+
+  def test_fail_api_auth_when_ip_not_allowed
+    with_config(:allow_anonymous_certs => false) do
+      allowed = "99.99.99.99"
+      new_config = {api_tokens: APP_CONFIG["api_tokens"].merge(allowed_ips: [allowed])}
+      with_config(new_config) do
+        monitor_auth do
+          request.env['REMOTE_ADDR'] = "1.1.1.1"
+          get :index
+          assert_nil assigns(:token), "should not be able to auth with api token when ip restriction doesn't allow it"
+          request.env['REMOTE_ADDR'] = allowed
+          get :index
+          assert assigns(:token), "should have authenticated via api token"
+        end
+      end
+    end
+  end
+
+end
+
diff --git a/test/integration/api/signup_test.rb b/test/integration/api/signup_test.rb
index 236c547..7216496 100644
--- a/test/integration/api/signup_test.rb
+++ b/test/integration/api/signup_test.rb
@@ -1,4 +1,4 @@
-require 'test_helper'
+require_relative '../../test_helper'
 require_relative 'srp_test'
 
 class SignupTest < SrpTest
@@ -8,7 +8,7 @@ class SignupTest < SrpTest
   end
 
   test "signup response" do
-    assert_json_response :login => @login, :ok => true
+    assert_json_response :login => @login, :ok => true, :id => @user.id, :enabled => true
     assert last_response.successful?
   end
 
-- 
cgit v1.2.3