api: Don't include API tokens in logs.
authorBrett Smith <brett@curoverse.com>
Fri, 11 Apr 2014 14:14:12 +0000 (10:14 -0400)
committerBrett Smith <brett@curoverse.com>
Fri, 11 Apr 2014 14:14:12 +0000 (10:14 -0400)
Refs #2375.  See Tom's comments.

I also renamed UNLOGGED_ATTRIBUTES to UNLOGGED_CHANGES to help clarify
that it's not used by logged_attributes.

services/api/app/models/api_client_authorization.rb
services/api/app/models/arvados_model.rb
services/api/app/models/log.rb
services/api/test/unit/log_test.rb

index 38a90d5c136aade3a355e5eb91ea1a02b58b5083..3b73f408c3f03bf35f48a0711357a0487fdeee8e 100644 (file)
@@ -20,8 +20,7 @@ class ApiClientAuthorization < ArvadosModel
     t.add :scopes
   end
 
-  UNLOGGED_ATTRIBUTES = ['last_used_at', 'last_used_by_ip_address',
-                         'updated_at']
+  UNLOGGED_CHANGES = ['last_used_at', 'last_used_by_ip_address', 'updated_at']
 
   def assign_random_api_token
     self.api_token ||= rand(2**256).to_s(36)
@@ -63,6 +62,12 @@ class ApiClientAuthorization < ArvadosModel
   end
   def modified_at=(x) end
 
+  def logged_attributes
+    attrs = attributes.dup
+    attrs.delete('api_token')
+    attrs
+  end
+
   protected
 
   def permission_to_create
@@ -76,6 +81,6 @@ class ApiClientAuthorization < ArvadosModel
   end
 
   def log_update
-    super unless (changed - UNLOGGED_ATTRIBUTES).empty?
+    super unless (changed - UNLOGGED_CHANGES).empty?
   end
 end
index a87e2d55f6830af42df1e110d957cf2a9ade4ee8..921d2b17c5152ed04fc742459cf927652056e14e 100644 (file)
@@ -87,6 +87,10 @@ class ArvadosModel < ActiveRecord::Base
             user.uuid)
   end
 
+  def logged_attributes
+    attributes
+  end
+
   protected
 
   def ensure_permission_to_create
@@ -216,7 +220,7 @@ class ArvadosModel < ActiveRecord::Base
 
   def log_start_state
     @old_etag = etag
-    @old_attributes = attributes
+    @old_attributes = logged_attributes
   end
 
   def log_change(event_type)
index e9fe35267590c77459b55278edf5085975bc92dc..af0b533c7525c8ad20fcbfb252c5d25047d01662 100644 (file)
@@ -29,7 +29,7 @@ class Log < ArvadosModel
   end
 
   def update_to(thing)
-    fill_properties('new', thing.andand.etag, thing.andand.attributes)
+    fill_properties('new', thing.andand.etag, thing.andand.logged_attributes)
     case event_type
     when "create"
       self.event_at = thing.created_at
index 6f793afe7ce2757ce22f3b7f69fb190cef2097ed..28980335788414076a642c221f39a25fac6cbd65 100644 (file)
@@ -55,6 +55,17 @@ class LogTest < ActiveSupport::TestCase
     yield props if block_given?
   end
 
+  def assert_auth_logged_with_clean_properties(auth, event_type)
+    assert_logged(auth, event_type) do |props|
+      ['old_attributes', 'new_attributes'].map { |k| props[k] }.compact
+        .each do |attributes|
+        refute_includes(attributes, 'api_token',
+                        "auth log properties include sensitive API token")
+      end
+      yield props if block_given?
+    end
+  end
+
   def set_user_from_auth(auth_name)
     client_auth = api_client_authorizations(auth_name)
     Thread.current[:api_client_authorization] = client_auth
@@ -96,6 +107,7 @@ class LogTest < ActiveSupport::TestCase
     auth = api_client_authorizations(:spectator)
     orig_etag = auth.etag
     orig_attrs = auth.attributes
+    orig_attrs.delete 'api_token'
     auth.destroy
     assert_logged(auth, :destroy) do |props|
       assert_equal(orig_etag, props['old_etag'], "destroyed auth etag mismatch")
@@ -199,4 +211,18 @@ class LogTest < ActiveSupport::TestCase
     auth.save!
     assert_logged(auth, :update)
   end
+
+  test "token isn't included in ApiClientAuthorization logs" do
+    set_user_from_auth :admin_trustedclient
+    auth = ApiClientAuthorization.new
+    auth.user = users(:spectator)
+    auth.api_client = api_clients(:untrusted)
+    auth.save!
+    assert_auth_logged_with_clean_properties(auth, :create)
+    auth.expires_at = Time.now
+    auth.save!
+    assert_auth_logged_with_clean_properties(auth, :update)
+    auth.destroy
+    assert_auth_logged_with_clean_properties(auth, :destroy)
+  end
 end