Skip to content

Commit

Permalink
Add JWT Authentication support and Error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
HyphenHook committed Jan 30, 2024
1 parent 681d3f6 commit f7de25a
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 25 deletions.
46 changes: 45 additions & 1 deletion src/Form/TripleStoreIndexerConfigForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

namespace Drupal\triplestore_indexer\Form;

use Drupal\advancedqueue\Entity\Queue;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\advancedqueue\Entity\Queue;
use Drupal\Core\Url;

/**
* Class TripleStoreIndexerConfigForm definition.
Expand Down Expand Up @@ -66,6 +67,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#options' => [
'-1' => 'None',
'digest' => 'Basic Authentication',
'jwt' => 'JWT Authentication',
],
'#ajax' => [
'wrapper' => 'questions-fieldset-wrapper',
Expand Down Expand Up @@ -109,6 +111,24 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#description' => $this->t('To reset the password, change Method of authentication to None first.'),
];
break;

case 'jwt':
$jwt_key = \Drupal::config('jwt.config')->get('key_id');
$key_repository = \Drupal::service('key.repository');
$key = $key_repository->getKey($jwt_key);
if (\Drupal::hasService('jwt.authentication.jwt') && $key != NULL) {
$form['container']['triplestore-server-config']['auth-config']['jwt_available'] = [
'#markup' => $this->t('JWT service is available.'),
];
}
else {
$url = Url::fromRoute('jwt.jwt_config_form')->toString();
$form['container']['triplestore-server-config']['auth-config']['jwt_error'] = [
'#markup' => $this->t('JWT service is not available. Please ensure you have enabled the JWT module and configured the key. <a href="@url">Click here</a> to configure JWT.', ['@url' => $url]),
];
}
break;

default:
$form['container']['triplestore-server-config']['auth-config']['question'] = [
'#markup' => $this->t('None.'),
Expand Down Expand Up @@ -218,6 +238,20 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
$form_state->setErrorByName("advancedqueue_id",
new FormattableMarkup('This queue\'s machine name "' . $form_state->getValues()['advancedqueue_id'] . '" is not valid, please verify it by <a href="/admin/config/system/queues">clicking here</a>.', []));
}

// Validate JWT availability.
if ($form_state->getValues()['select-auth-method'] === 'jwt') {
// Use key_id from jwt module configuration to check if it is available.
$jwt_key = \Drupal::config('jwt.config')->get('key_id');
$key_repository = \Drupal::service('key.repository');
// Check if the key is in key repository.
$key = $key_repository->getKey($jwt_key);
if (!\Drupal::hasService('jwt.authentication.jwt') || $key == NULL) {
$url = Url::fromRoute('jwt.jwt_config_form')->toString();
$form_state->setErrorByName("select-auth-method",
new FormattableMarkup('JWT service is not available. Please ensure you have enabled the JWT module and configured the key. <a href="@url">Click here</a> to configure JWT.', ['@url' => $url]));
}
}
}

/**
Expand All @@ -240,9 +274,18 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$configFactory->set('admin_password', base64_encode($form_state->getValues()['admin_password']));
}
break;

case 'jwt':
if (\Drupal::hasService('jwt.authentication.jwt')) {
$jwt_token = \Drupal::service('jwt.authentication.jwt')->generateToken();
$configFactory->set('jwt_token', $jwt_token);
}
break;

default:
$configFactory->set('admin_username', NULL);
$configFactory->set('admin_password', NULL);
$configFactory->set('jwt_token', NULL);
break;
}

Expand All @@ -267,4 +310,5 @@ public function promptAuthCallback(array $form, FormStateInterface $form_state)
public function promptOpCallback(array $form, FormStateInterface $form_state) {
return $form['container']['triplestore-server-config']['op-config'];
}

}
56 changes: 39 additions & 17 deletions src/IndexingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,24 @@ public function serialization(array $payload) {
// Make GET request to any content with _format=jsonld.
$config = \Drupal::config('triplestore_indexer.settings');
$uri = "$base_url/$type/$nid" . '?_format=jsonld';

if ($config->get("method_of_auth") == 'digest') {
$headers = [
'auth' => [$config->get('admin_username'),base64_decode($config->get('admin_password'))]
];
$request = \Drupal::httpClient()->get($uri, $headers);
} else {
$request = \Drupal::httpClient()->get($uri);
switch ($config->get("method_of_auth")) {
case 'digest':
$headers = [
'auth' => [$config->get('admin_username'), base64_decode($config->get('admin_password'))],
];
$request = \Drupal::httpClient()->get($uri, $headers);
break;

case 'jwt':
$headers = [
'Authorization' => 'Bearer ' . $config->get('jwt_token'),
];
$request = \Drupal::httpClient()->get($uri, ['headers' => $headers]);
break;

default:
$request = \Drupal::httpClient()->get($uri);
break;
}
$graph = $request->getBody();
return $graph;
Expand All @@ -42,18 +52,30 @@ public function getOtherConmponentAssocNode(array $payload) {
// Make GET request to any content with _format=jsonld.
$uri = "$base_url/$type/$nid" . '?_format=jsonld';

// add header if there is authentication is needed
// Add header if there is authentication is needed.
$config = \Drupal::config('triplestore_indexer.settings');
if ($config->get("method_of_auth") == 'digest') {
$headers = [
'auth' => [$config->get('admin_username'),base64_decode($config->get('admin_password'))]
];
$request = \Drupal::httpClient()->get($uri, $headers);
} else {
$request = \Drupal::httpClient()->get($uri);

switch ($config->get("method_of_auth")) {
case 'digest':
$headers = [
'auth' => [$config->get('admin_username'), base64_decode($config->get('admin_password'))],
];
$request = \Drupal::httpClient()->get($uri, $headers);
break;

case 'jwt':
$headers = [
'Authorization' => 'Bearer ' . $config->get('jwt_token'),
];
$request = \Drupal::httpClient()->get($uri, ['headers' => $headers]);
break;

default:
$request = \Drupal::httpClient()->get($uri);
break;
}

// get response body
// Get response body.
$graph = ((array) json_decode($request->getBody()))['@graph'];
$others = [];
for ($i = 1; $i < count($graph); $i++) {
Expand Down
81 changes: 74 additions & 7 deletions triplestore_indexer.module
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
* Contains triplestore_indexer.module.
*/

use Drupal\taxonomy\Entity\Term;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\advancedqueue\Entity\Queue;
use Drupal\advancedqueue\Job;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\taxonomy\Entity\Term;
use GuzzleHttp\Exception\ClientException;

/**
* Implements hook_help().
Expand Down Expand Up @@ -46,6 +49,70 @@ function triplestore_indexer_entity_insert(EntityInterface $entity) {
drupal_register_shutdown_function('execute_indexing_action', 'index_node_to_triplestore_advancedqueue', $entity);
}

/**
* Implements hook_form_alter().
*/
function triplestore_indexer_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// Matching the form id to node_[content_type]_delete_form.
// Adding validator only to the content type that is indexed.
if (preg_match('/^node_(.*)_delete_form$/', $form_id, $matches)) {
$originalId = $matches[1];
$config = \Drupal::config('triplestore_indexer.settings');
$indexed_content = $config->get('content_type_to_index');
if (is_array($config->get('content_type_to_index')) && in_array($originalId, $indexed_content)) {
$form['#validate'][] = 'triplestore_indexer_node_delete_form_validate';
}
}
}

/**
* Validation handler for node delete forms.
*/
function triplestore_indexer_node_delete_form_validate($form, FormStateInterface $form_state) {
global $base_url;
$node = $form_state->getFormObject()->getEntity();
$url = $node->toUrl()->toString();
$uri = $base_url . $url . '?_format=jsonld';
$config = \Drupal::config('triplestore_indexer.settings');
try {
switch ($config->get("method_of_auth")) {
case 'digest':
$headers = [
'auth' => [$config->get('admin_username'), base64_decode($config->get('admin_password'))],
];
\Drupal::httpClient()->get($uri, $headers);
break;

case 'jwt':
$headers = [
'Authorization' => 'Bearer ' . $config->get('jwt_token'),
];
\Drupal::httpClient()->get($uri, ['headers' => $headers]);
break;

default:
\Drupal::httpClient()->get($uri);
break;
}
}
catch (Exception $e) {
if ($e instanceof ClientException && $e->getCode() > 400 && $e->getCode() < 500) {
// Handling 4XX errors.
$triplestore_url = Url::fromRoute('triplestore_indexer.triplestore_indexer_config_form')->toString();
$form_state->setErrorByName('delete', t('Access Control is in place for this item. <a href="@url">Click here</a> to add authentication to Triplestore Indexer in order to proceed deletion.', ['@url' => $triplestore_url]));
}
elseif (str_contains($e->getResponse()->getBody()->getContents(), 'getKey()')) {
// Handling JWT key missing.
$jwt_url = Url::fromRoute('jwt.jwt_config_form')->toString();
$form_state->setErrorByName('delete', t('An error occurred: Your JWT Authentication Configurations are invalid! <a href="@url">Click Here</a> to configure them.', ['@url' => $jwt_url]));
}
else {
// General error.
$form_state->setErrorByName('delete', t('An error occurred: @error', ['@error' => $e->getMessage()]));
}
}
}

/**
* Implements hook_entity_update().
*/
Expand All @@ -57,11 +124,11 @@ function triplestore_indexer_entity_update(EntityInterface $entity) {
* Implements hook_entity_delete().
*/
function triplestore_indexer_entity_predelete(EntityInterface $entity) {
// both failed
// Both failed.
execute_indexing_action('delete_node_in_triplestore_advancedqueue', $entity);

// delete content work, but delete indexed content in blazegraph works
//drupal_register_shutdown_function('execute_indexing_action', 'delete_node_in_triplestore_advancedqueue', $entity);
// Delete content work, but delete indexed content in blazegraph works.
// drupal_register_shutdown_function('execute_indexing_action', 'delete_node_in_triplestore_advancedqueue', $entity);
}

/**
Expand Down

0 comments on commit f7de25a

Please sign in to comment.