From 64eac5879fe80f9ad52665421962740390a14eee Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Tue, 1 Sep 2020 15:21:54 -0400 Subject: [PATCH] 16726: Initialize anonymous user token in arvados-boot Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- lib/boot/seed.go | 4 ++ lib/boot/supervisor.go | 4 ++ lib/controller/integration_test.go | 67 +++++++++++++++++++ .../api/script/get_anonymous_user_token.rb | 48 ++++++++----- 4 files changed, 105 insertions(+), 18 deletions(-) diff --git a/lib/boot/seed.go b/lib/boot/seed.go index d1cf2a8709..2afccc45b6 100644 --- a/lib/boot/seed.go +++ b/lib/boot/seed.go @@ -24,5 +24,9 @@ func (seedDatabase) Run(ctx context.Context, fail func(error), super *Supervisor if err != nil { return err } + err = super.RunProgram(ctx, "services/api", nil, railsEnv, "bundle", "exec", "./script/get_anonymous_user_token.rb") + if err != nil { + return err + } return nil } diff --git a/lib/boot/supervisor.go b/lib/boot/supervisor.go index 3f4fb74822..3484a1444e 100644 --- a/lib/boot/supervisor.go +++ b/lib/boot/supervisor.go @@ -617,6 +617,10 @@ func (super *Supervisor) autofillConfig(cfg *arvados.Config) error { if cluster.Collections.BlobSigningKey == "" { cluster.Collections.BlobSigningKey = randomHexString(64) } + if cluster.Users.AnonymousUserToken == "" { + cluster.Users.AnonymousUserToken = randomHexString(64) + } + if super.ClusterType != "production" && cluster.Containers.DispatchPrivateKey == "" { buf, err := ioutil.ReadFile(filepath.Join(super.SourcePath, "lib", "dispatchcloud", "test", "sshkey_dispatch")) if err != nil { diff --git a/lib/controller/integration_test.go b/lib/controller/integration_test.go index a73f5f9f82..0708ab3e70 100644 --- a/lib/controller/integration_test.go +++ b/lib/controller/integration_test.go @@ -139,10 +139,15 @@ func (s *IntegrationSuite) TearDownSuite(c *check.C) { } } +// Get rpc connection struct initialized to communicate with the +// specified cluster. func (s *IntegrationSuite) conn(clusterID string) *rpc.Conn { return rpc.NewConn(clusterID, s.testClusters[clusterID].controllerURL, true, rpc.PassthroughTokenProvider) } +// Return Context, Arvados.Client and keepclient structs initialized +// to connect to the specified cluster (by clusterID) using with the supplied +// Arvados token. func (s *IntegrationSuite) clientsWithToken(clusterID string, token string) (context.Context, *arvados.Client, *keepclient.KeepClient) { cl := s.testClusters[clusterID].config.Clusters[clusterID] ctx := auth.NewContext(context.Background(), auth.NewCredentials(token)) @@ -159,6 +164,10 @@ func (s *IntegrationSuite) clientsWithToken(clusterID string, token string) (con return ctx, ac, kc } +// Log in as a user called "example", get the user's API token, +// initialize clients with the API token, set up the user and +// optionally activate the user. Return client structs for +// communicating with the cluster on behalf of the 'example' user. func (s *IntegrationSuite) userClients(rootctx context.Context, c *check.C, conn *rpc.Conn, clusterID string, activate bool) (context.Context, *arvados.Client, *keepclient.KeepClient) { login, err := conn.UserSessionCreate(rootctx, rpc.UserSessionCreateOptions{ ReturnTo: ",https://example.com", @@ -192,10 +201,18 @@ func (s *IntegrationSuite) userClients(rootctx context.Context, c *check.C, conn return ctx, ac, kc } +// Return Context, arvados.Client and keepclient structs initialized +// to communicate with the cluster as the system root user. func (s *IntegrationSuite) rootClients(clusterID string) (context.Context, *arvados.Client, *keepclient.KeepClient) { return s.clientsWithToken(clusterID, s.testClusters[clusterID].config.Clusters[clusterID].SystemRootToken) } +// Return Context, arvados.Client and keepclient structs initialized +// to communicate with the cluster as the anonymous user. +func (s *IntegrationSuite) anonymousClients(clusterID string) (context.Context, *arvados.Client, *keepclient.KeepClient) { + return s.clientsWithToken(clusterID, s.testClusters[clusterID].config.Clusters[clusterID].Users.AnonymousUserToken) +} + func (s *IntegrationSuite) TestGetCollectionByPDH(c *check.C) { conn1 := s.conn("z1111") rootctx1, _, _ := s.rootClients("z1111") @@ -234,6 +251,56 @@ func (s *IntegrationSuite) TestGetCollectionByPDH(c *check.C) { c.Check(coll.PortableDataHash, check.Equals, pdh) } +func (s *IntegrationSuite) TestGetCollectionAsAnonymous(c *check.C) { + conn1 := s.conn("z1111") + conn3 := s.conn("z3333") + rootctx1, ac1, kc1 := s.rootClients("z1111") + userctx3, ac3, _ := s.anonymousClients("z3333") + + // Make sure anonymous token was set + c.Assert(ac3.AuthToken, check.Not(check.Equals), "") + + // Create the collection to find its PDH (but don't save it + // anywhere yet) + var coll1 arvados.Collection + fs1, err := coll1.FileSystem(ac1, kc1) + c.Assert(err, check.IsNil) + f, err := fs1.OpenFile("test.txt", os.O_CREATE|os.O_RDWR, 0777) + c.Assert(err, check.IsNil) + _, err = io.WriteString(f, "IntegrationSuite.TestGetCollectionByPDH") + c.Assert(err, check.IsNil) + err = f.Close() + c.Assert(err, check.IsNil) + mtxt, err := fs1.MarshalManifest(".") + c.Assert(err, check.IsNil) + pdh := arvados.PortableDataHash(mtxt) + + // Save the collection on cluster z1111. + coll1, err = conn1.CollectionCreate(rootctx1, arvados.CreateOptions{Attrs: map[string]interface{}{ + "manifest_text": mtxt, + }}) + c.Assert(err, check.IsNil) + + // Share it with the anonymous users group. + var outLink arvados.Link + err = ac1.RequestAndDecode(&outLink, "POST", "/arvados/v1/links", nil, &arvados.Link{ + LinkClass: "permission", + Name: "can_read", + HeadUUID: coll1.UUID, + TailUUID: "z1111-j7d0g-anonymouspublic", + }) + c.Check(err, check.IsNil) + + outUser, err := ac3.CurrentUser() + c.Check(err, check.IsNil) + c.Check(outUser.UUID, check.Equals, "z3333-tpzed-anonymouspublic") + + // Retrieve the collection as anonymous from cluster z3333. + coll, err := conn3.CollectionGet(userctx3, arvados.GetOptions{UUID: pdh}) + c.Check(err, check.IsNil) + c.Check(coll.PortableDataHash, check.Equals, pdh) +} + // Get a token from the login cluster (z1111), use it to submit a // container request on z2222. func (s *IntegrationSuite) TestCreateContainerRequestWithFedToken(c *check.C) { diff --git a/services/api/script/get_anonymous_user_token.rb b/services/api/script/get_anonymous_user_token.rb index 4bb91e2446..8775ae5959 100755 --- a/services/api/script/get_anonymous_user_token.rb +++ b/services/api/script/get_anonymous_user_token.rb @@ -29,27 +29,37 @@ include ApplicationHelper act_as_system_user def create_api_client_auth(supplied_token=nil) + supplied_token = Rails.configuration.Users["AnonymousUserToken"] - # If token is supplied, see if it exists - if supplied_token - api_client_auth = ApiClientAuthorization. - where(api_token: supplied_token). - first - if !api_client_auth - # fall through to create a token - else - raise "Token exists, aborting!" + if supplied_token.nil? or supplied_token.empty? + puts "Users.AnonymousUserToken is empty. Destroying tokens that belong to anonymous." + # Token is empty. Destroy any anonymous tokens. + ApiClientAuthorization.where(user: anonymous_user).destroy_all + return nil + end + + attr = {user: anonymous_user, + api_client_id: 0, + scopes: ['GET /']} + + secret = supplied_token + + if supplied_token[0..2] == 'v2/' + _, token_uuid, secret, optional = supplied_token.split('/') + if token_uuid[0..4] != Rails.configuration.ClusterID + # Belongs to a different cluster. + puts supplied_token + return nil end + attr[:uuid] = token_uuid end - api_client_auth = ApiClientAuthorization. - new(user: anonymous_user, - api_client_id: 0, - expires_at: Time.now + 100.years, - scopes: ['GET /'], - api_token: supplied_token) - api_client_auth.save! - api_client_auth.reload + attr[:api_token] = secret + + api_client_auth = ApiClientAuthorization.where(attr).first + if !api_client_auth + api_client_auth = ApiClientAuthorization.create!(attr) + end api_client_auth end @@ -67,4 +77,6 @@ if !api_client_auth end # print it to the console -puts api_client_auth.api_token +if api_client_auth + puts "v2/#{api_client_auth.uuid}/#{api_client_auth.api_token}" +end -- 2.30.2