3

In my class, I have the following request:

    $rest_response = $client->post($endpoint, [
      'auth' => ['admin', 'admin'],
      'body' => $serialized_entity,
      'headers' => [
        'Content-Type' => 'application/hal+json',
        'X-CSRF-Token' => $token,
      ],
    ]);

It works because I have a user with the username/password as "admin"/"admin", but when that user's password is changed, it won't work anymore, as expected.

In the logs, I am getting an "access denied" error for the endpoint I am trying to POST to - and the user associated with that error says "Anonymous (not verified)". All other log messages printed out in my controller show the current user's username.

I am running Drupal core 8.1.9.

The question is - how do I use basic_auth to get the current logged-in user's credentials to be passed into the request?

1
  • That would require getting the user's password in plaintext, which isn't possible
    – Clive
    Commented Dec 13, 2016 at 15:26

2 Answers 2

4

You were so close main thing here is the "Authorization" Header ...

 $current_user = \Drupal::currentUser();
 $account = $current_user->getAccount();

 $username = $account->name;
 // pass would be hard to get as stored hashed 
 //... so you would need to get a bit tricky to "catch" the users password when they log in... 
 $pass = 'admin';
 $auth = 'Basic '. base64_encode ($username . ':' . $pass);
 $rest_response = $client->post($endpoint, [
   'body' => $serialized_entity,
   'headers' => [
     'Authorization' => $auth,
     'Content-Type' => 'application/hal+json',
     'X-CSRF-Token' => $token,
  ],
]);

And just for fun:

  var basicAuthCredential = username + ":" + password;
  var bace64 =  btoa(basicAuthCredential);
  var Auth =  'Basic ' + bace64;
  fetch(url,{
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': Auth,
      'X-CSRF-Token': token
    },
    body: JSON.stringify(data)
}).then(response => response.json())...
1
  • Inside a PHPUnit test, you can use $user->passRaw to get the password, which can be useful for authenticating automatically generated accounts. Commented Sep 12 at 22:56
0

I was able to figure out a workaround solution that solved my question. First, I had to allow "Anonymous" users the permission to POST to my custom REST resource. This allowed my resource to be accessed by the POST request programmatically-called by my Guzzle client.
In my REST resource, I am checking for the user's permission, which restrict access for users without the permissions defined (in my case, "access content").

/**
 * Provides a resource to get bundles by entity.
 *
 * @RestResource(
 *   id = "distribution_content_ingestion",
 *   label = @Translation("Distribution Content Ingestion"),
 *   serialization_class = "Drupal\my_module\Normalizer\JsonDenormalizer",
 *   uri_paths = {
 *     "canonical" = "/entity/distribution_ingest/{distribution_id}",
 *     "https://www.drupal.org/link-relations/create" = "/entity/distribution_ingest/{distribution_id}"
 *   }
 * )
 */
class DistributionIngestResource extends ResourceBase {
  /**
   * A current user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Constructs a Drupal\rest\Plugin\ResourceBase object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param array $serializer_formats
   *   The available serialization formats.
   * @param \Psr\Log\LoggerInterface $logger
   *   A logger instance.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   A current user instance.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    array $serializer_formats,
    LoggerInterface $logger,
    AccountProxyInterface $current_user) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

    $this->currentUser = $current_user;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('rest'),
      $container->get('current_user')
    );
  }

  /**
   * Responds to POST requests.
   *
   * Returns a list of bundles for specified entity.
   *
   * @param string $distribution_id
   *   The Distribution ID to ingest.
   * @param array $data
   *   The data from the POST.
   *
   * @return \Drupal\rest\ResourceResponse
   *   Throws exception expected.
   */
  public function post($distribution_id, $data) {
    // You must to implement the logic of your REST Resource here.
    // Use current user after pass authentication to validate access.
    if (!$this->currentUser->hasPermission('access content')) {
      throw new AccessDeniedHttpException();
    }

    /**
     * Some code here.
     */
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.