Problem/Motivation

As done in #2856713: Authentication plugins and HTTP authentication, there are now authentication plugins.

In the configuration there is now an UUID used to store sensible data locally in a state:

entity_share_client.remote.*:
  type: config_entity
  label: 'Remote config'
  mapping:
    ...
    auth:
      type: mapping
      mapping:
        pid:
          label: 'Plugin ID'
          type: string
        uuid:
          label: 'UUID'
          type: string

And there is the entity_share_client_update_8201 that handles the update.

I was thinking about it and I think it will provoke problems with multiple environments.

Because the UUID generated will be different per environment, when using a config import, the UUID will then differ from the one used to create the state. So the login/password saved in the state will no more be usable (at least without custom code or custom config overrides using settings.php or something else to force UUID).

Proposed resolution

  • Use the remote config entity's UUID, so that it won't change per environment.
  • Use a dedicated key_value collection and no more state for local storage

Also this will ease managing config overrides in settings.php, config_split, or anything else and will ease scripting for example local storage key value creation.

Remaining tasks

  • Discuss about this issue
  • See if there won't be any other problem
  • Create a patch

Comments

Grimreaper created an issue. See original summary.

fathershawn’s picture

Because the UUID generated will be different per environment, when using a config import, the UUID will then differ from the one used to create the state.

Perhaps I'm missing a link in the logic chain, but I don't think this is correct. Here's how I see it.

A Remote is created and the authorization plugin is chosen. The configuration for this plugin, including its UUID is included as a child of the remote's config:

uuid: ce866f4e-ba8b-4e2c-9038-800e2ac1fb23
langcode: en
status: true
dependencies: {  }
id: test_remote
label: 'Test Remote'
url: 'http://example.com'
auth:
  pid: oauth
  uuid: 33f847c6-4024-4d7b-b5d8-df95a398c4dc
  verified: false
  data:
    credential_provider: entity_share
    storage_key: 33f847c6-4024-4d7b-b5d8-df95a398c4dc

When \Drupal\entity_share_client\Entity\Remote::getAuthPlugin is run the plugin configuration is loaded:

/**
   * {@inheritdoc}
   */
  public function getAuthPlugin() {
    $pluginData = $this->auth;
    if (!empty($pluginData['pid'])) {
      // DI not available in entities:
      // https://www.drupal.org/project/drupal/issues/2142515.
      /** @var \Drupal\entity_share_client\Plugin\ClientAuthorizationManager $manager */
      $manager = \Drupal::service('plugin.manager.entity_share_auth');
      $pluginId = $pluginData['pid'];
      unset($pluginData['pid']);
      return $manager->createInstance($pluginId, $pluginData);
    }
    return NULL;
  }

The plugin id is extracted from this array so that the remaining keys form a configuration array, and the plugin is loaded with this config. Once the plugin has been created the UUID is persistent.

What varies by environment is the value stored in State. But in my view it should vary, especially for Oauth. Each environment should be using it's own consumer on the hub. I'm fairly certain that a variety of issues that I saw in testing were the result of environment B getting a new token from the same consumer used by environment A, causing the requests from A to fail because they were sharing a consumer and the token stored by A had been invalidated by the new token creation for B.

grimreaper’s picture

Thanks @FatherShawn for the reply.

Yes, when creating a remote configuration and deploying it, the UUID in:

auth:
  pid: basic_auth
  uuid: 33f847c6-4024-4d7b-b5d8-df95a398c4dc

will not change, but my concern is about the update entity_share_client_update_8201().

As it will change the remote configurations from the previous structure to the new one, it will create new uuids the time to run the update, then when using configuration management, when doing "drush config:import" it will the UUID from the versionned config entity.

So if on the development environment (A), I have:

uuid: ce866f4e-ba8b-4e2c-9038-800e2ac1fb23
auth:
  pid: basic_auth
  uuid: 33f847c6-4024-4d7b-b5d8-df95a398c4dc

on this environment, there will be a state with 33f847c6-4024-4d7b-b5d8-df95a398c4dc, that will store the data: OK

When on another environment (B), executing entity_share_client_update_8201(), will give:

uuid: ce866f4e-ba8b-4e2c-9038-800e2ac1fb23
auth:
  pid: basic_auth
  uuid: something-else

And so there will be a state "something-else" that will store the data, then config import will transform it back to:

uuid: ce866f4e-ba8b-4e2c-9038-800e2ac1fb23
auth:
  pid: basic_auth
  uuid: 33f847c6-4024-4d7b-b5d8-df95a398c4dc

But there will not be a state "33f847c6-4024-4d7b-b5d8-df95a398c4dc" created on environment B: KO

I agree that you can then go on environment B and save the remote form so the state "33f847c6-4024-4d7b-b5d8-df95a398c4dc" will be created, but:
1. the update is here to avoid manual steps
2. "something-else" will be "orphan" and will stay indefinitely in the database.

Is my concern better expressed like this?

(also I am definitely for a dedicated key_value collection and no more a state otherwise it is impossible to clean things when uninstalling the module or to clean it for another reason)

fathershawn’s picture

Thanks for clarifying. Now I understand. I do like the idea of a dedicated key-value collection. That's a great idea that accomplishes the intent of my use of State but with all the benefits that you name.

I'll have a close look at the update hook to see if I have a suggestion for this case.

fathershawn’s picture

StatusFileSize
new2.01 KB

See what you think of this approach?

grimreaper’s picture

Thanks @FatherShawn for the reply.

Hum, I think in comment 5 you are trying to handle something else. But it gave me the solution for the update.

Please see attached patch.

Also I tested to delete a remote config entity and the state is not deleted.

So if the update is ok for you next step will be (I will do it if I have the time) to switch from state to key value collection and implement an hook to clean it when the config entity is deleted.

fathershawn’s picture

As I read your approach, it is to always use the same uuid in the update, so if there is a config import following, and that config is from an update that took place in a prior environment, it overwrites the uuid with the same value. Result: only one value is stored.

My code was aiming to solve the problem a different way, but your way is simpler. I like it.

Will the key/value change be in this issue or another?

grimreaper’s picture

Thanks for your feedback :)

Hum, update aside, with the current codebase in the dev version, when you import configuration the state is not updated.

So maybe it is how your sentence "and that config is from an update" is done, I am not 100% sure that we are talking about the same thing. But as you are ok with my proposition I guess it is the same thing finally :D

Yes it will be in this issue that the key_value change will happen. :)

grimreaper’s picture

Assigned: Unassigned » grimreaper
Status: Active » Needs work
grimreaper’s picture

Title: Update concern regarding UUID in Remote config entity » Update concern regarding UUID in Remote config entity and switch to key value store
Status: Needs work » Needs review
StatusFileSize
new15.93 KB

Hello,

And here is the patch. Testing manually while triggerring Drupal CI.

Status: Needs review » Needs work

The last submitted patch, 10: entity_share-update_concern-3172390-10.patch, failed testing. View results

grimreaper’s picture

I forgot the hook to delete the key_value when the config is deleted.

And when switching authentication method, a new UUID is generated so the previous key_value is not deleted.

grimreaper’s picture

Status: Needs work » Needs review
StatusFileSize
new20.69 KB
new5.35 KB
grimreaper’s picture

I have just realized that the "password" form element on the Basic Auth plugin was not of type password.

grimreaper’s picture

Assigned: grimreaper » Unassigned

Hi @FatherShawn,

Waiting for your review before merging and making the first beta release :)

fathershawn’s picture

I can see why you want to use a common value for the auth plugin uuid in RemoteForm when a plugin has been previously stored. I had the get past the idea that in one sense it was no longer "universally unique." But we are really using it as a storage key.

        // Ensure all plugins will have the same uuid in the configuration to
        // avoid duplication of entries in the key value store.
        if (!is_null($this->authPlugin)) {
          $existing_plugin_configuration = $this->authPlugin->getConfiguration();
          $plugin_configuration = $plugin->getConfiguration();
          $plugin_configuration['uuid'] = $existing_plugin_configuration['uuid'];
          $plugin->setConfiguration($plugin_configuration);
        }

However, I think this is better handled by `ClientAuthorizationPluginManager::getAvailablePlugins`.

In ClientAuthorization we are inconsistent with the value of the key used for storing into KeyValue, and I see some other inconsistencies about when values are set and deleted. For example, in some places `-oauth` is appended to the end of the uuid to make a key and in some not. Some of that may trace back to my original draft, or the blending of our code. I'm auditing all the places that we store or retrieve and refactoring it to be consistent.

I have a proposed patch in progress but I'm being pulled back into client work that's needed first and then I'll circle back

grimreaper’s picture

Status: Needs review » Needs work

Thanks @FatherShawn for the feedback!

Waiting for your patch.

And no problem about priority to client work. We are used to that too ;)

fathershawn’s picture

Status: Needs work » Needs review
StatusFileSize
new22.04 KB
new4.62 KB

With fresh eyes the "inconsistency" that I thought I saw was in my memory and not the code. I added some comments instead. But I did move the common uuid process as discussed above. Here's a patch against the latest 3.x with an interdiff as well.

grimreaper’s picture

Hello @FatherShawn,

I really like your approach of the new argument in getAvailablePlugins().

The point on Oauth plugin made me make a little adjustment in entity_share_client_remote_delete().

A last review and I think we are done with this issue.

fathershawn’s picture

Almost, or we could be done depending on what you think. Good catch on Oauth having secondary storage. That prompts me to say that perhaps we should establish a convention of using the plugin id and make this more general. I've refactored one more time with that in mind.

grimreaper’s picture

Nice idea! Thanks!

Doing a last manual testing and then merge and then release!!!

  • FatherShawn authored 45dd17c on 8.x-3.x
    Issue #3172390 by Grimreaper, FatherShawn: Update concern regarding UUID...
  • Grimreaper authored 6acd2c0 on 8.x-3.x
    Issue #3172390 by Grimreaper, FatherShawn: Update concern regarding UUID...
grimreaper’s picture

Status: Needs review » Fixed

And this is merged now!

Thanks for your help!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.