2659: split server side implementation into a separate branch to facilitate better...
authorradhika <radhika@curoverse.com>
Fri, 27 Jun 2014 13:41:08 +0000 (09:41 -0400)
committerradhika <radhika@curoverse.com>
Fri, 27 Jun 2014 13:41:08 +0000 (09:41 -0400)
services/api/app/models/user.rb
services/api/db/migrate/20140627210837_anonymous_group.rb [new file with mode: 0644]
services/api/db/schema.rb
services/api/db/seeds.rb
services/api/lib/current_api_client.rb
services/api/script/get_anonymous_user_token.rb [new file with mode: 0755]
services/api/test/fixtures/api_client_authorizations.yml
services/api/test/fixtures/groups.yml
services/api/test/fixtures/links.yml
services/api/test/fixtures/users.yml
services/api/test/unit/user_test.rb

index 52dd8d79ff47014a9bfe0896a818b28c4d83395d..677685d67abdb60270b113ffeb46d6bb5edea81c 100644 (file)
@@ -41,7 +41,11 @@ class User < ArvadosModel
   end
 
   def groups_i_can(verb)
-    self.group_permissions.select { |uuid, mask| mask[verb] }.keys
+    my_groups = self.group_permissions.select { |uuid, mask| mask[verb] }.keys
+    if verb == :read
+      my_groups << anonymous_group_uuid
+    end
+    my_groups
   end
 
   def can?(actions)
diff --git a/services/api/db/migrate/20140627210837_anonymous_group.rb b/services/api/db/migrate/20140627210837_anonymous_group.rb
new file mode 100644 (file)
index 0000000..0bb7608
--- /dev/null
@@ -0,0 +1,17 @@
+class AnonymousGroup < ActiveRecord::Migration
+  include CurrentApiClient
+
+  def up
+    # create the anonymous group and user
+    anonymous_group
+    anonymous_user
+  end
+
+  def down
+    act_as_system_user do
+      anonymous_user.destroy
+      anonymous_group.destroy
+    end
+  end
+
+end
index 1f9b5019ab60a528ba72434d4d91190783195bef..256fa3977eb3aa458be00b1805fc40a1c6f68cdf 100644 (file)
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20140611173003) do
+ActiveRecord::Schema.define(:version => 20140627210837) do
 
 
 
index 1f17bc84e63c0cb5a2734762e34510ac4324448b..abd325c724267c76a5a4e11e696bdc62c60ee483 100644 (file)
@@ -2,8 +2,10 @@
 #
 # It is invoked by `rake db:seed` and `rake db:setup`.
 
-# These two methods would create the system user and group objects on
-# demand later anyway, but it's better form to create them up front.
+# These two methods would create these objects on demand
+# later anyway, but it's better form to create them up front.
 include CurrentApiClient
 system_user
 system_group
+anonymous_group
+anonymous_user
index f851c588c7445ef7d180bee1896b9f2e0bfc7d36..c5581502cf3b9e5eaa66f74271ed72c8998604ea 100644 (file)
@@ -41,6 +41,18 @@ module CurrentApiClient
      '000000000000000'].join('-')
   end
 
+  def anonymous_group_uuid
+    [Server::Application.config.uuid_prefix,
+     Group.uuid_prefix,
+     'anonymouspublic'].join('-')
+  end
+
+  def anonymous_user_uuid
+    [Server::Application.config.uuid_prefix,
+     User.uuid_prefix,
+     'anonymouspublic'].join('-')
+  end
+
   def system_user
     if not $system_user
       real_current_user = Thread.current[:user]
@@ -99,4 +111,51 @@ module CurrentApiClient
       Thread.current[:user] = system_user
     end
   end
+
+  def anonymous_group
+    if not $anonymous_group
+      act_as_system_user do
+        ActiveRecord::Base.transaction do
+          $anonymous_group = Group.
+          where(uuid: anonymous_group_uuid).first_or_create do |g|
+            g.update_attributes(name: "Anonymous group",
+                                description: "Anonymous group")
+          end
+        end
+      end
+    end
+    $anonymous_group
+  end
+
+  def anonymous_user
+    if not $anonymous_user
+      act_as_system_user do
+        $anonymous_user = User.where('uuid=?', anonymous_user_uuid).first
+        if !$anonymous_user
+          $anonymous_user = User.new(uuid: anonymous_user_uuid,
+                                     is_active: false,
+                                     is_admin: false,
+                                     email: 'anonymouspublic',
+                                     first_name: 'anonymouspublic',
+                                     last_name: 'anonymouspublic')
+          $anonymous_user.save!
+          $anonymous_user.reload
+
+          group_perms = Link.where(tail_uuid: anonymous_user_uuid,
+                                   head_uuid: anonymous_group_uuid,
+                                   link_class: 'permission',
+                                   name: 'can_read')
+
+          if !group_perms.any?
+            group_perm = Link.create(tail_uuid: anonymous_user_uuid,
+                                   head_uuid: anonymous_group_uuid,
+                                   link_class: 'permission',
+                                   name: 'can_read')
+          end
+        end
+      end
+    end
+    $anonymous_user
+  end
+
 end
diff --git a/services/api/script/get_anonymous_user_token.rb b/services/api/script/get_anonymous_user_token.rb
new file mode 100755 (executable)
index 0000000..76e2088
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env ruby
+
+# Get or Create an anonymous user token.
+# If get option is used, an existing anonymous user token is returned. If none exist, one is created.
+# If the get option is omitted, a new token is created and returned.
+
+require 'trollop'
+
+opts = Trollop::options do
+  banner ''
+  banner "Usage: get_anonymous_user_token "
+  banner ''
+  opt :get, <<-eos
+Get an existing anonymous user token. If no such token exists \
+or if this option is omitted, a new token is created and returned.
+  eos
+end
+
+get_existing = opts[:get]
+
+require File.dirname(__FILE__) + '/../config/environment'
+
+include ApplicationHelper
+act_as_system_user
+
+def create_api_client_auth
+  api_client_auth = ApiClientAuthorization.
+    new(user: anonymous_user,
+        api_client_id: 0,
+        scopes: ['GET /'])
+  api_client_auth.save!
+  api_client_auth.reload
+end
+
+if get_existing
+  api_client_auth = ApiClientAuthorization.
+    where('user_id=?', anonymous_user.id.to_i).first
+end
+
+# either not a get or no api_client_auth was found
+if !api_client_auth
+  api_client_auth = create_api_client_auth
+end
+
+# print it to the console
+puts api_client_auth.api_token
index 71b638806d4188dbf3257cd8851c10dfaa7f1f73..d1743b73c1f8663c9f1ffc723e053dc0ae96e62e 100644 (file)
@@ -136,3 +136,10 @@ valid_token_deleted_user:
   user_id: 1234567
   api_token: tewfa58099sndckyqhlgd37za6e47o6h03r9l1vpll23hudm8b
   expires_at: 2038-01-01 00:00:00
+
+anonymous:
+  api_client: untrusted
+  user: anonymous
+  api_token: 4kg6k6lzmp9kj4cpkcoxie964cmvjahbt4fod9zru44k4jqdmi
+  expires_at: 2038-01-01 00:00:00
+  scopes: ["GET /"]
index e41ca8a5c5cf4ed9edc4ee407acde14dd7f693f6..cd6157bdd84a6a41be6edf48c9298360ecd98c31 100644 (file)
@@ -87,3 +87,16 @@ bad_group_has_ownership_cycle_b:
   modified_at: 2014-05-03 18:50:08 -0400
   updated_at: 2014-05-03 18:50:08 -0400
   name: Owned by bad group a
+
+anonymous_group:
+  uuid: zzzzz-j7d0g-anonymouspublic
+  owner_uuid: zzzzz-tpzed-000000000000000
+  name: Anonymous group
+  description: Anonymous group
+
+anonymously_accessible_project:
+  uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  owner_uuid: zzzzz-tpzed-d9tiejq69daie8f
+  name: Unrestricted public data
+  group_class: project
+  description: An anonymously accessible project
index b35e7d47844c2933b4b30f0cb41075005919a613..5911230f48f3d387070a088e1d9eade3f189bd8c 100644 (file)
@@ -441,6 +441,59 @@ bug2931_link_with_null_head_uuid:
   head_uuid: ~
   properties: {}
 
+anonymous_group_can_read_anonymously_accessible_project:
+  uuid: zzzzz-o0j2j-15gpzezqjg4bc4z
+  owner_uuid: zzzzz-tpzed-000000000000000
+  created_at: 2014-05-30 14:30:00.184389725 Z
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-000000000000000
+  modified_at: 2014-05-30 14:30:00.184019565 Z
+  updated_at: 2014-05-30 14:30:00.183829316 Z
+  link_class: permission
+  name: can_read
+  tail_uuid: zzzzz-j7d0g-anonymouspublic
+  head_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  properties: {}
+
+user_agreement_in_anonymously_accessible_project:
+  uuid: zzzzz-o0j2j-k0ukddp35mt6ok1
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  created_at: 2014-06-13 20:42:26 -0800
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+  modified_at: 2014-06-13 20:42:26 -0800
+  updated_at: 2014-06-13 20:42:26 -0800
+  link_class: name
+  name: GNU General Public License, version 3
+  tail_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  head_uuid: b519d9cb706a29fc7ea24dbea2f05851+249025
+  properties: {}
+
+user_agreement_readable_by_anonymously_accessible_project:
+  uuid: zzzzz-o0j2j-o5ds5gvhkztdc8h
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  created_at: 2014-06-13 20:42:26 -0800
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+  modified_at: 2014-06-13 20:42:26 -0800
+  updated_at: 2014-06-13 20:42:26 -0800
+  link_class: permission
+  name: can_read
+
+share_the_aproject_with_all_groups:
+  uuid: zzzzz-o0j2j-24gpzezqjg4bc4z
+  owner_uuid: zzzzz-tpzed-000000000000000
+  created_at: 2014-05-30 14:30:00.184389725 Z
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-000000000000000
+  modified_at: 2014-05-30 14:30:00.184019565 Z
+  updated_at: 2014-05-30 14:30:00.183829316 Z
+  link_class: permission
+  name: can_read
+  tail_uuid: zzzzz-j7d0g-anonymouspublic
+  head_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+  properties: {}
+
 active_user_permission_to_docker_image_collection:
   uuid: zzzzz-o0j2j-dp1d8395ldqw33s
   owner_uuid: zzzzz-tpzed-000000000000000
index c02ab61aa66b26cec3d96f08f3ad6c2d96fcd630..ac76d5fa47124ef5a5fc17fc1870804b7c532680 100644 (file)
@@ -80,3 +80,11 @@ inactive_but_signed_user_agreement:
   is_admin: false
   prefs: {}
 
+anonymous:
+  uuid: zzzzz-tpzed-anonymouspublic
+  email: anonymouspublic
+  first_name: anonymouspublic
+  last_name: anonymouspublic
+  is_active: false
+  is_admin: false
+  prefs: {}
index 8f0277909a4126826be910d635ab809c1225a836..d4f25245c31e182a2895a4b4b6480cbaee4f7220 100644 (file)
@@ -60,7 +60,8 @@ class UserTest < ActiveSupport::TestCase
     assert @uninvited_user.can? :write=>"#{@uninvited_user.uuid}"
     assert @uninvited_user.can? :manage=>"#{@uninvited_user.uuid}"
 
-    assert @uninvited_user.groups_i_can(:read).size == 0, "inactive and uninvited user should not be able read any groups"
+    assert @uninvited_user.groups_i_can(:read).size == 1, "inactive and uninvited user can only read anonymous user group"
+    assert @uninvited_user.groups_i_can(:read).first.ends_with? 'anonymouspublic' , "inactive and uninvited user can only read anonymous user group"
     assert @uninvited_user.groups_i_can(:write).size == 0, "inactive and uninvited user should not be able write to any groups"
     assert @uninvited_user.groups_i_can(:manage).size == 0, "inactive and uninvited user should not be able manage any groups"
   end