16923: Add "TrustedClients" configuration option.
authorPeter Amstutz <peter.amstutz@curii.com>
Tue, 29 Sep 2020 23:12:50 +0000 (19:12 -0400)
committerPeter Amstutz <peter.amstutz@curii.com>
Thu, 1 Oct 2020 14:40:53 +0000 (10:40 -0400)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

lib/config/config.default.yml
lib/config/generated_config.go
sdk/go/arvados/config.go
services/api/app/models/api_client.rb
services/api/config/arvados_config.rb
services/api/test/unit/api_client_test.rb

index d0338e8c86636480dc9640c9683039f2a94b1603..04a1dafa346d29c5fd92e206f6da449c2f94cd8a 100644 (file)
@@ -727,6 +727,17 @@ Clusters:
       # Default value zero means tokens don't have expiration.
       TokenLifetime: 0s
 
+      # When the token is returned to a client, the token itself may
+      # be restricted from manipulating other tokens based on whether
+      # the client is "trusted" or not.  The local Workbench1 are
+      # trusted by default, but if this is a LoginCluster, you
+      # probably want to include the Workbench instances in the
+      # federation in this list.
+      TrustedClients:
+        SAMPLE:
+          "https://workbench.federate1.example": {}
+          "https://workbench.federate2.example": {}
+
     Git:
       # Path to git or gitolite-shell executable. Each authenticated
       # request will execute this program with the single argument "http-backend"
index 88d71eb0ac83b76c38cbeedc0df8456eba70bf52..2b81f28c645569d3fe04f3bafe88e5f20fe7f6b2 100644 (file)
@@ -733,6 +733,17 @@ Clusters:
       # Default value zero means tokens don't have expiration.
       TokenLifetime: 0s
 
+      # When the token is returned to a client, the token itself may
+      # be restricted from manipulating other tokens based on whether
+      # the client is "trusted" or not.  The local Workbench1 are
+      # trusted by default, but if this is a LoginCluster, you
+      # probably want to include the Workbench instances in the
+      # federation in this list.
+      TrustedClients:
+        SAMPLE:
+          "https://workbench.federate1.example": {}
+          "https://workbench.federate2.example": {}
+
     Git:
       # Path to git or gitolite-shell executable. Each authenticated
       # request will execute this program with the single argument "http-backend"
index 00438bf340a36851ff48262d6df998ce9407f112..27a4c1de3db83888bccaa2dd8ff5faabb697f408 100644 (file)
@@ -183,6 +183,7 @@ type Cluster struct {
                LoginCluster       string
                RemoteTokenRefresh Duration
                TokenLifetime      Duration
+               TrustedClients     map[string]struct{}
        }
        Mail struct {
                MailchimpAPIKey                string
index c9eeaf2669192a9e3178b0c613609dd49d77a6d7..015b61dc494c1c7b3cff629407cb0ebdc0ff656c 100644 (file)
@@ -22,14 +22,27 @@ class ApiClient < ArvadosModel
 
   def from_trusted_url
     norm_url_prefix = norm(self.url_prefix)
-    norm_url_prefix == norm(Rails.configuration.Services.Workbench1.ExternalURL) or
-      norm_url_prefix == norm(Rails.configuration.Services.Workbench2.ExternalURL) or
-      norm_url_prefix == norm("https://controller.api.client.invalid")
+
+    [Rails.configuration.Services.Workbench1.ExternalURL,
+     Rails.configuration.Services.Workbench2.ExternalURL,
+     "https://controller.api.client.invalid"].each do |url|
+      if norm_url_prefix == norm(url)
+        return true
+      end
+    end
+
+    Rails.configuration.Login.TrustedClients.keys.each do |url|
+      if norm_url_prefix == norm(url)
+        return true
+      end
+    end
+
+    false
   end
 
   def norm url
     # normalize URL for comparison
-    url = URI(url)
+    url = URI(url.to_s)
     if url.scheme == "https"
       url.port == "443"
     end
index 4f831160e9351790143505cc16447e6d0507b0e3..69b20420abac9c0c52ccb5aefbccbbfc3110b194 100644 (file)
@@ -110,6 +110,7 @@ arvcfg.declare_config "Users.NewInactiveUserNotificationRecipients", Hash, :new_
 arvcfg.declare_config "Login.SSO.ProviderAppSecret", String, :sso_app_secret
 arvcfg.declare_config "Login.SSO.ProviderAppID", String, :sso_app_id
 arvcfg.declare_config "Login.LoginCluster", String
+arvcfg.declare_config "Login.TrustedClients", Hash
 arvcfg.declare_config "Login.RemoteTokenRefresh", ActiveSupport::Duration
 arvcfg.declare_config "Login.TokenLifetime", ActiveSupport::Duration
 arvcfg.declare_config "TLS.Insecure", Boolean, :sso_insecure
index 93e4c51abf0e9266a1883ab18bf5634ea45722b0..bf47cd175bcd5790930d55b67af74c1664d60926 100644 (file)
@@ -12,6 +12,8 @@ class ApiClientTest < ActiveSupport::TestCase
       Rails.configuration.Login.TokenLifetime = token_lifetime_enabled ? 8.hours : 0
       Rails.configuration.Services.Workbench1.ExternalURL = URI("http://wb1.example.com")
       Rails.configuration.Services.Workbench2.ExternalURL = URI("https://wb2.example.com:443")
+      Rails.configuration.Login.TrustedClients = ActiveSupport::OrderedOptions.new
+      Rails.configuration.Login.TrustedClients[:"https://wb3.example.com"] = ActiveSupport::OrderedOptions.new
 
       act_as_system_user do
         [["http://wb0.example.com", false],
@@ -19,6 +21,8 @@ class ApiClientTest < ActiveSupport::TestCase
         ["http://wb2.example.com", false],
         ["https://wb2.example.com", true],
         ["https://wb2.example.com/", true],
+        ["https://wb3.example.com/", true],
+        ["https://wb4.example.com/", false],
         ].each do |pfx, result|
           a = ApiClient.create(url_prefix: pfx, is_trusted: false)
           if token_lifetime_enabled