Skip to content

Commit

Permalink
dispatch...
Browse files Browse the repository at this point in the history
  • Loading branch information
Ioannis committed May 2, 2025
1 parent c67fbd2 commit 357e5c9
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,11 @@ msgstr "Obtained ORCID {0} via authenticated OAuth flow"

msgid "information.orcid_source.identifier"
msgstr "ORCID Identifier"

msgid "information.OrcidSourceCollectors.authenticate"
msgstr "Authenticate with ORCID"

msgid "information.OrcidSourceCollectors.sign_in"
msgstr "Sign in with your ORCID account to securely verify your ORCID iD."


Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,27 @@
use OrcidSource\Lib\Enum\OrcidSourceScopeEnum;

class OrcidSourceCollectorsController extends StandardEnrollerController {
protected $OrcidSources;

public $paginate = [
'order' => [
'OrcidSourceCollectors.id' => 'asc'
]
];

/**
* Callback run prior to the request action.
*
* @since COmanage Registry v5.2.0
* @param EventInterface $event Cake Event
*/
public function beforeFilter(\Cake\Event\EventInterface $event)
{
$this->OrcidSources = TableRegistry::getTableLocator()->get('OrcidSource.OrcidSources');

return parent::beforeFilter($event);
}

/**
* Callback run prior to the request render.
*
Expand Down Expand Up @@ -85,26 +100,46 @@ public function dispatch(string $id) {

$this->set('vv_op', $op);

$oricdSource = $this->OrcidSourceCollectors->get(
$oricdSourceEntity = $this->OrcidSourceCollectors->get(
(int)$id,
[
'contain' => [
'ExternalIdentitySources' => ['OrcidSources' => ['Servers']]
]]
);

$ServerModel = $oricdSource->external_identity_source->orcid_source->server->plugin;
$PluginServers = $this->getTableLocator()->get($ServerModel);
$ServerModel = $oricdSourceEntity->external_identity_source->orcid_source->server->plugin;
$PluginServersTable = TableRegistry::getTableLocator()->get($ServerModel);
$serverId = $oricdSourceEntity->external_identity_source->orcid_source->server->id;
$PluginServerEntity = $PluginServersTable ->find()
->where(['server_id' => $serverId])
->first();

$oauthServer = $this->Oauth2Servers->get($oricdSource->external_identity_source->orcid_source->server->id);

$this->set('vv_config', $oricdSource);
$this->set('vv_config', $oricdSourceEntity);
$this->set('vv_config_server', $PluginServerEntity);
$this->set('controller', $this);


try {
// Let's authenticate first
$this->authenticate($id, $oricdSource, $code);
if ($op == 'authenticate') {
$this->authenticate($id, $PluginServerEntity);
} else if (!empty($code)) {
$response = $PluginServersTable->exchangeCode(
$id,
$code,
$this->OrcidSources->redirectUri(
[
$id,
'?' => ['petition_id' => $petition->id],
]
),
);

// Use the response and save the data to petitions table
} else {
// Fall Through. Let the view render
}

}
catch(\OverflowException $e) {
Expand All @@ -125,58 +160,37 @@ public function dispatch(string $id) {


/**
* Authenticate using OAuth2 Authorization Code flow.
* Authenticate the user with ORCID OAuth2 server
*
* This method handles the OAuth2 authentication process by:
* 1. Building callback URL for the OAuth2 redirect
* 2. Redirecting to authorization endpoint on first access
* 3. Exchanging authorization code for access token on callback
*
* @param string|int $id Orcid Source Collector ID
* @param EntityInterface $oscfg Configuration array containing OAuth2 settings and OrgIdentitySource details
* @param string|null $code Authorization code returned from OAuth2 server (optional)
* @param string|int $id ID of the collector
* @param EntityInterface $serverCfg ORCID Server configuration
* @return void
* @since COmanage Registry v5.2.0
* @throws \Exception If authentication fails
* @throws \OverflowException If source key is already attached
* @since COmanage Registry v5.2.0
*/
protected function authenticate(string|int $id, EntityInterface $oscfg, ?string $code): void
protected function authenticate(string|int $id, EntityInterface $serverCfg): void
{
// We need a different callback URL than what the Oauth2Server config will
// use, since we're basically creating a runtime Authorization Code flow
// (while the main config uses a Client Credentials flow).

$callback = [
'plugin' => 'OrcidSource',
'controller' => 'OrcidSourcesCollectors',
'action' => 'dispatch',
$petition = $this->getPetition();
$callback = $this->OrcidSources->redirectUri([
$id,
'?' => ['osid' => $oscfg->id],
];

'?' => ['petition_id' => $petition->id],
]);
// Build the redirect URI
$redirectUri = Router::url($callback, true);

if (empty($code)) {
$scope = OrcidSourceScopeEnum::DEFAULT_SCOPE;
if (!empty($oscfg->scope_inherit)) {
$scope = $oscfg->scope_inherit;
}


// First time through, redirect to the "authorize" URL

$url = $oscfg->url . '/authorize?';
$url .= 'client_id=' . $oscfg->clientid;
$url .= '&response_type=code';
$url .= '&scope=' . str_replace(' ', '%20', $scope);
$url .= '&redirect_uri=' . urlencode($redirectUri);

$this->redirect($url);
$scope = OrcidSourceScopeEnum::DEFAULT_SCOPE;
if (!empty($serverCfg->scope_inherit)) {
$scope = $serverCfg->scope_inherit;
}

// $response = $this->Oauth2Server->exchangeCode($cfg['Oauth2Server']['id'],
// $this->request->query['code'],
// $redirectUri,
// false);
$url = $serverCfg->url . '/authorize?';
$url .= 'client_id=' . $serverCfg->clientid;
$url .= '&response_type=code';
$url .= '&scope=' . str_replace(' ', '%20', $scope);
$url .= '&redirect_uri=' . urlencode($redirectUri);

$this->redirect($url);
}

/**
Expand Down
17 changes: 12 additions & 5 deletions app/plugins/OrcidSource/src/Model/Table/OrcidSourcesTable.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/**
* COmanage Registry Env Sources Table
* COmanage Registry Orcid Sources Table
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
Expand Down Expand Up @@ -140,19 +140,26 @@ public function initialize(array $config): void {
]);
}


/**
* Generate a redirect URI.
* Get the OAuth2 redirect URI for ORCID callbacks
*
* @return string The full URL of the redirect URI
* @param array $extra Additional URL parameters to include in redirect
* @return string Full URL for OAuth2 redirect
* @since COmanage Registry v5.2.0
*/
public function redirectUri(): string
public function redirectUri(array $extra = []): string
{
$callback = [
'plugin' => 'OrcidSource',
'controller' => 'OrcidSourceCollectors',
'action' => 'dispatch',
];

if (!empty($extra)) {
$callback = array_merge($callback, $extra);
}

return Router::url($callback, true);
}

Expand Down Expand Up @@ -194,7 +201,7 @@ public function inventory(
*
* @since COmanage Registry v5.2.0
* @param OrcidSource $OrcidSource OrcidSource configuration entity
* @param array $result Array of Env attributes
* @param array $result Array of Orcid attributes
* @return array Entity record (in array format)
*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,34 @@ declare(strict_types = 1);
if($vv_action !== 'dispatch') {
return;
}

// Load view dependencies
$this->Html->css('OrcidSource/orcid-source', ['block' => true]);

// Make the Form fields editable
$this->Field->enableFormEditMode();
ksort($vv_orcid_source_vars);
$previousKey = '';

// The first time we will suppress default submit
$suppress_submit = true;
$btnAuthenticateLabel = '<span class="material-symbols-outlined my-auto me-1" aria-hidden="true">login</span>'
. __d('orcid_source', 'information.OrcidSourceCollectors.authenticate');

print $this->Form->hidden('op', ['value' => 'authenticate']);

// Render the parsed variables
?>
<div class="text-center py-3">
<img src="https://orcid.org/sites/default/files/images/orcid_128x128.png"
alt="ORCID logo"
class="mb-3"
style="width:72px;">
<h2 class="fw-bold mb-2" style="color:#68b245;">Authenticate with ORCID</h2>
<p class="mb-4 text-muted">Sign in with your ORCID account to securely verify your ORCID iD.</p>
<button id="orcid-auth-btn"
class="btn btn-success btn-lg mb-2 d-inline-flex align-items-center gap-1"
aria-label="Authenticate with ORCID">
<span class="material-symbols-outlined" aria-hidden="true" style="font-size: 22px; vertical-align: middle;">
login
</span>
Authenticate with ORCID
</button>
<div id="orcid-result" class="fw-medium mt-3" style="color:#198754;"></div>
<?= $this->Html->image('OrcidSource.orcid_128x128.png', ['alt' => 'Logo', 'class' => 'mb-3']) ?>
<h2 class="fw-bold mb-2"><?= __d('orcid_source', 'information.OrcidSourceCollectors.authenticate') ?></h2>
<p class="mb-4 text-muted"><?= __d('orcid_source', 'information.OrcidSourceCollectors.sign_in') ?></p>
<?= $this->Form->button(
$btnAuthenticateLabel,
[
'escapeTitle' => false,
'type' => 'submit',
'class' => 'spin submit-button btn btn-primary d-flex mx-auto',
]
)
?>
<div id="orcid-result" class="fw-medium mt-3"></div>
</div>

<script>
// Placeholder demo: show a fake ORCID iD when button is clicked
document.getElementById('orcid-auth-btn').onclick = function() {
document.getElementById('orcid-result').textContent =
"Authenticated ORCID iD: 0000-0002-1825-0097";
};
</script>
21 changes: 21 additions & 0 deletions app/plugins/OrcidSource/webroot/css/orcid-source.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.text-center img {
width: 72px;
}

.text-center h2 {
color: #68b245;
}

#orcid-auth-btn {
color: white;
font-weight: bolder;
}

.material-symbols-outlined {
font-size: 22px;
vertical-align: middle;
}

#orcid-result {
color: #198754;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 357e5c9

Please sign in to comment.