20750: DRY uncache token test code
[arvados.git] / services / api / test / integration / remote_user_test.rb
index 259d7f554ddbcf8f29168bd45502eaac63a7642f..f9e44c357a9f4b12701f153d20f538494c728323 100644 (file)
@@ -55,7 +55,6 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
         SSLCertName: [["CN", WEBrick::Utils::getservername]],
         StartCallback: lambda { ready.push(true) })
       srv.mount_proc '/discovery/v1/apis/arvados/v1/rest' do |req, res|
-        Rails.cache.delete 'arvados_v1_rest_discovery'
         res.body = Arvados::V1::SchemaController.new.send(:discovery_doc).to_json
       end
       srv.mount_proc '/arvados/v1/users/current' do |req, res|
@@ -67,9 +66,19 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
         res.status = @stub_status
         res.body = @stub_content.is_a?(String) ? @stub_content : @stub_content.to_json
       end
-      srv.mount_proc '/arvados/v1/users/register' do |req, res|
-        res.status = @stub_status
-        res.body = @stub_content.is_a?(String) ? @stub_content : @stub_content.to_json
+      srv.mount_proc '/arvados/v1/api_client_authorizations/current' do |req, res|
+        if clusterid == 'zbbbb' and req.header['authorization'][0][10..14] == 'zbork'
+          # asking zbbbb about zbork should yield an error, zbbbb doesn't trust zbork
+          res.status = 401
+          return
+        end
+        res.status = @stub_token_status
+        if res.status == 200
+          res.body = {
+            uuid: api_client_authorizations(:active).uuid.sub('zzzzz', clusterid),
+            scopes: @stub_token_scopes,
+          }.to_json
+        end
       end
       Thread.new do
         srv.start
@@ -83,12 +92,15 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
     Arvados::V1::SchemaController.any_instance.stubs(:root_url).returns "https://#{@remote_host[0]}"
     @stub_status = 200
     @stub_content = {
-      uuid: 'zbbbb-tpzed-000000000000000',
+      uuid: 'zbbbb-tpzed-000000000000001',
       email: 'foo@example.com',
       username: 'barney',
       is_admin: true,
       is_active: true,
+      is_invited: true,
     }
+    @stub_token_status = 200
+    @stub_token_scopes = ["all"]
   end
 
   teardown do
@@ -97,12 +109,43 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
     end
   end
 
+  def uncache_token(src)
+    if match = src.match(/\b(?:[a-z0-9]{5}-){2}[a-z0-9]{15}\b/)
+      tokens = ApiClientAuthorization.where(uuid: match[0])
+    else
+      tokens = ApiClientAuthorization.where("uuid like ?", "#{src}-%")
+    end
+    tokens.update_all(expires_at: "1995-05-15T01:02:03Z")
+  end
+
+  test 'authenticate with remote token that has limited scope' do
+    get '/arvados/v1/collections',
+        params: {format: 'json'},
+        headers: auth(remote: 'zbbbb')
+    assert_response :success
+
+    @stub_token_scopes = ["GET /arvados/v1/users/current"]
+
+    # re-authorize before cache expires
+    get '/arvados/v1/collections',
+        params: {format: 'json'},
+        headers: auth(remote: 'zbbbb')
+    assert_response :success
+
+    uncache_token('zbbbb')
+    # re-authorize after cache expires
+    get '/arvados/v1/collections',
+        params: {format: 'json'},
+        headers: auth(remote: 'zbbbb')
+    assert_response 403
+  end
+
   test 'authenticate with remote token' do
     get '/arvados/v1/users/current',
       params: {format: 'json'},
       headers: auth(remote: 'zbbbb')
     assert_response :success
-    assert_equal 'zbbbb-tpzed-000000000000000', json_response['uuid']
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
     assert_equal false, json_response['is_admin']
     assert_equal false, json_response['is_active']
     assert_equal 'foo@example.com', json_response['email']
@@ -117,11 +160,7 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
       headers: auth(remote: 'zbbbb')
     assert_response :success
 
-    # simulate cache expiry
-    ApiClientAuthorization.where(
-      uuid: salted_active_token(remote: 'zbbbb').split('/')[1]).
-      update_all(expires_at: db_current_time - 1.minute)
-
+    uncache_token('zbbbb')
     # re-authorize after cache expires
     get '/arvados/v1/users/current',
       params: {format: 'json'},
@@ -147,6 +186,27 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
     assert_equal 'blarney@example.com', json_response['email']
   end
 
+  test 'remote user is deactivated' do
+    Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = true
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal true, json_response['is_active']
+
+    # revoke original token
+    @stub_content[:is_active] = false
+    @stub_content[:is_invited] = false
+
+    uncache_token('zbbbb')
+    # re-authorize after cache expires
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_equal false, json_response['is_active']
+
+  end
+
   test 'authenticate with remote token, remote username conflicts with local' do
     @stub_content[:username] = 'active'
     get '/arvados/v1/users/current',
@@ -242,6 +302,7 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
   end
 
   test "list readable groups with salted token" do
+    Rails.configuration.Users.RoleGroupsVisibleToAll = false
     salted_token = salt_token(fixture: :active, remote: 'zbbbb')
     get '/arvados/v1/groups',
       params: {
@@ -259,27 +320,163 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
     refute_includes(group_uuids, groups(:testusergroup_admins).uuid)
   end
 
+  test 'do not auto-activate user from untrusted cluster' do
+    Rails.configuration.RemoteClusters['zbbbb'].AutoSetupNewUsers = false
+    Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = false
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+    assert_equal false, json_response['is_admin']
+    assert_equal false, json_response['is_active']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+    post '/arvados/v1/users/zbbbb-tpzed-000000000000001/activate',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response 422
+  end
+
   test 'auto-activate user from trusted cluster' do
     Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = true
     get '/arvados/v1/users/current',
       params: {format: 'json'},
       headers: auth(remote: 'zbbbb')
     assert_response :success
-    assert_equal 'zbbbb-tpzed-000000000000000', json_response['uuid']
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+    assert_equal false, json_response['is_admin']
+    assert_equal true, json_response['is_active']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+  end
+
+  test 'get user from Login cluster' do
+    Rails.configuration.Login.LoginCluster = 'zbbbb'
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+    assert_equal true, json_response['is_admin']
+    assert_equal true, json_response['is_active']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+  end
+
+  [true, false].each do |trusted|
+    [true, false].each do |logincluster|
+      [true, false].each do |admin|
+        [true, false].each do |active|
+          [true, false].each do |autosetup|
+            [true, false].each do |invited|
+              test "get invited=#{invited}, active=#{active}, admin=#{admin} user from #{if logincluster then "Login" else "peer" end} cluster when AutoSetupNewUsers=#{autosetup} ActivateUsers=#{trusted}" do
+                Rails.configuration.Login.LoginCluster = 'zbbbb' if logincluster
+                Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = trusted
+                Rails.configuration.Users.AutoSetupNewUsers = autosetup
+                @stub_content = {
+                  uuid: 'zbbbb-tpzed-000000000000001',
+                  email: 'foo@example.com',
+                  username: 'barney',
+                  is_admin: admin,
+                  is_active: active,
+                  is_invited: invited,
+                }
+                get '/arvados/v1/users/current',
+                    params: {format: 'json'},
+                    headers: auth(remote: 'zbbbb')
+                assert_response :success
+                assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+                assert_equal (logincluster && admin && invited && active), json_response['is_admin']
+                assert_equal (invited and (logincluster || trusted || autosetup)), json_response['is_invited']
+                assert_equal (invited and (logincluster || trusted) and active), json_response['is_active']
+                assert_equal 'foo@example.com', json_response['email']
+                assert_equal 'barney', json_response['username']
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+
+  test 'get active user from Login cluster when AutoSetupNewUsers is set' do
+    Rails.configuration.Login.LoginCluster = 'zbbbb'
+    Rails.configuration.Users.AutoSetupNewUsers = true
+    @stub_content = {
+      uuid: 'zbbbb-tpzed-000000000000001',
+      email: 'foo@example.com',
+      username: 'barney',
+      is_admin: false,
+      is_active: true,
+      is_invited: true,
+    }
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
     assert_equal false, json_response['is_admin']
     assert_equal true, json_response['is_active']
+    assert_equal true, json_response['is_invited']
     assert_equal 'foo@example.com', json_response['email']
     assert_equal 'barney', json_response['username']
+
+    @stub_content = {
+      uuid: 'zbbbb-tpzed-000000000000001',
+      email: 'foo@example.com',
+      username: 'barney',
+      is_admin: false,
+      is_active: false,
+      is_invited: false,
+    }
+
+    # Use cached value.  User will still be active because we haven't
+    # re-queried the upstream cluster.
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+    assert_equal false, json_response['is_admin']
+    assert_equal true, json_response['is_active']
+    assert_equal true, json_response['is_invited']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+
+    uncache_token('zbbbb')
+    # User should be inactive now.
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
+    assert_equal false, json_response['is_admin']
+    assert_equal false, json_response['is_active']
+    assert_equal false, json_response['is_invited']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+
   end
 
   test 'pre-activate remote user' do
+    @stub_content = {
+      uuid: 'zbbbb-tpzed-000000000001234',
+      email: 'foo@example.com',
+      username: 'barney',
+      is_admin: true,
+      is_active: true,
+      is_invited: true,
+    }
+
     post '/arvados/v1/users',
       params: {
         "user" => {
-          "uuid" => "zbbbb-tpzed-000000000000000",
+          "uuid" => "zbbbb-tpzed-000000000001234",
           "email" => 'foo@example.com',
           "username" => 'barney',
-          "is_active" => true
+          "is_active" => true,
+          "is_admin" => false
         }
       },
       headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_token(:admin)}"}
@@ -289,13 +486,35 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
       params: {format: 'json'},
       headers: auth(remote: 'zbbbb')
     assert_response :success
-    assert_equal 'zbbbb-tpzed-000000000000000', json_response['uuid']
-    assert_equal nil, json_response['is_admin']
+    assert_equal 'zbbbb-tpzed-000000000001234', json_response['uuid']
+    assert_equal false, json_response['is_admin']
     assert_equal true, json_response['is_active']
     assert_equal 'foo@example.com', json_response['email']
     assert_equal 'barney', json_response['username']
   end
 
+
+  test 'remote user inactive without pre-activation' do
+    @stub_content = {
+      uuid: 'zbbbb-tpzed-000000000001234',
+      email: 'foo@example.com',
+      username: 'barney',
+      is_admin: true,
+      is_active: true,
+      is_invited: true,
+    }
+
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zbbbb-tpzed-000000000001234', json_response['uuid']
+    assert_equal false, json_response['is_admin']
+    assert_equal false, json_response['is_active']
+    assert_equal 'foo@example.com', json_response['email']
+    assert_equal 'barney', json_response['username']
+  end
+
   test "validate unsalted v2 token for remote cluster zbbbb" do
     auth = api_client_authorizations(:active)
     token = "v2/#{auth.uuid}/#{auth.api_token}"
@@ -331,4 +550,22 @@ class RemoteUsersTest < ActionDispatch::IntegrationTest
     end
   end
 
+  test 'authenticate with remote token, remote user is system user' do
+    @stub_content[:uuid] = 'zbbbb-tpzed-000000000000000'
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_equal 'from cluster zbbbb', json_response['last_name']
+  end
+
+  test 'authenticate with remote token, remote user is anonymous user' do
+    @stub_content[:uuid] = 'zbbbb-tpzed-anonymouspublic'
+    get '/arvados/v1/users/current',
+      params: {format: 'json'},
+      headers: auth(remote: 'zbbbb')
+    assert_response :success
+    assert_equal 'zzzzz-tpzed-anonymouspublic', json_response['uuid']
+  end
+
+
 end