-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 43da773
Showing
11 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: lint-test | ||
|
||
on: | ||
push: | ||
branches: | ||
- '**' | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
lint-test: | ||
name: lint+test | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
php-version: ["8.1", "8.2", "8.3"] | ||
drupal-version: ["10.3", "10.4", "11.0"] | ||
exclude: | ||
- drupal-version: "11.0" | ||
php-version: "8.1" | ||
- drupal-version: "11.0" | ||
php-version: "8.2" | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: lint+test | ||
working-directory: tests | ||
run: | | ||
export MODULE_DIRECTORY=$(pwd | xargs dirname) | ||
docker compose up --quiet-pull --abort-on-container-exit | ||
env: | ||
DRUPAL_VERSION: ${{ matrix.drupal-version }} | ||
PHP_VERSION: ${{ matrix.php-version }} | ||
ENABLE_MODULES: islandora_jwks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: Mirror to drupal.org | ||
on: | ||
push: | ||
branches: | ||
- 1.x | ||
tags: | ||
- '*' | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- name: Mirror + trigger CI | ||
uses: SvanBoxel/gitlab-mirror-and-ci-action@master | ||
with: | ||
args: "https://git.drupalcode.org/project/islandora_jwks" | ||
env: | ||
FOLLOW_TAGS: "true" | ||
FORCE_PUSH: "false" | ||
GITLAB_HOSTNAME: "git.drupal.org" | ||
GITLAB_USERNAME: "foo" | ||
GITLAB_PASSWORD: ${{ secrets.GITLAB_PASSWORD }} | ||
GITLAB_PROJECT_ID: "173125" | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: Create release | ||
on: | ||
pull_request_target: | ||
branches: | ||
- 1.x | ||
types: | ||
- closed | ||
permissions: | ||
contents: write | ||
actions: write | ||
jobs: | ||
release: | ||
if: github.event.pull_request.merged == true | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: install autotag binary | ||
run: curl -sL https://git.io/autotag-install | sudo sh -s -- -b /usr/bin | ||
|
||
- name: create release | ||
run: |- | ||
TAG=$(autotag) | ||
git tag $TAG | ||
git push origin $TAG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
## INTRODUCTION | ||
|
||
The Islandora JWKS module provides a JWKS URI for Islandora's JWT tokens at `/oauth/discovery/keys`. | ||
|
||
## REQUIREMENTS | ||
|
||
- drupal/jwt | ||
- drupal/islandora | ||
|
||
## INSTALLATION | ||
|
||
Install as you would normally install a contributed Drupal module. | ||
See: https://www.drupal.org/node/895232 for further information. | ||
|
||
## CONFIGURATION | ||
- Ensure your JWT public key is available at `/var/run/s6/container_environment/JWT_PUBLIC_KEY`. If using [isle-buildkit](https://github.com/islandora-devops/isle-buildkit) to run your Islandora site this will be handled automatically for you. | ||
|
||
## MAINTAINERS | ||
|
||
Current maintainers for Drupal 10: | ||
|
||
- Joe Corall (joecorall) - https://www.drupal.org/u/joecorall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"name": "drupal/islandora_jwks", | ||
"description": "Provide a JWKS URI for Islandora's JWT tokens", | ||
"type": "drupal-module", | ||
"license": "GPL-2.0+", | ||
"homepage": "https://www.drupal.org/project/islandora_jwks", | ||
"support": { | ||
"issues": "https://www.drupal.org/project/issues/islandora_jwks" | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Joe Corall", | ||
"email": "[email protected]", | ||
"role": "Owner" | ||
} | ||
], | ||
"require" : { | ||
"drupal/islandora": "^2.13" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
name: 'Islandora JWKS' | ||
type: module | ||
description: 'Provide a JWKS URI for Islandora's JWT tokens' | ||
package: Islandora | ||
core_version_requirement: ^10 || ^11 | ||
dependencies: | ||
- islandora:islandora | ||
- jwt:jwt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Primary module hooks for Islandora JWKS module. | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
islandora_jwks.uri: | ||
path: '/oauth/discovery/keys' | ||
defaults: | ||
_title: 'Keys' | ||
_controller: '\Drupal\islandora_jwks\Controller\IslandoraJwksController' | ||
requirements: | ||
_permission: 'access content' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\islandora_jwks\Controller; | ||
|
||
use Drupal\Core\Controller\ControllerBase; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
/** | ||
* Returns responses for Islandora JWKS routes. | ||
*/ | ||
class IslandoraJwksController extends ControllerBase { | ||
|
||
/** | ||
* Builds the JWKS response. | ||
*/ | ||
public function __invoke(): JsonResponse { | ||
$keyPath = '/var/run/s6/container_environment/JWT_PUBLIC_KEY'; | ||
|
||
$publicKey = $this->readPublicKey($keyPath); | ||
if ($publicKey === NULL) { | ||
return new JsonResponse(['error' => 'Public key not found'], Response::HTTP_INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
$opensslKey = openssl_pkey_get_public($publicKey); | ||
if ($opensslKey === FALSE) { | ||
return new JsonResponse(['error' => 'Invalid RSA public key'], Response::HTTP_INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
$details = openssl_pkey_get_details($opensslKey); | ||
if (!$details || !isset($details['rsa'])) { | ||
return new JsonResponse(['error' => 'Failed to extract RSA key details'], Response::HTTP_INTERNAL_SERVER_ERROR); | ||
} | ||
$jwks = [ | ||
'keys' => [ | ||
[ | ||
'kty' => 'RSA', | ||
'kid' => sha1($publicKey), | ||
'use' => 'sig', | ||
'alg' => 'RS256', | ||
'n' => $this->base64UrlEncode($details['rsa']['n']), | ||
'e' => $this->base64UrlEncode($details['rsa']['e']), | ||
], | ||
], | ||
]; | ||
|
||
return new JsonResponse($jwks, Response::HTTP_OK); | ||
} | ||
|
||
/** | ||
* Reads the public key from disk. | ||
*/ | ||
protected function readPublicKey(string $path): ?string { | ||
return is_readable($path) ? trim(file_get_contents($path)) : NULL; | ||
} | ||
|
||
/** | ||
* Encodes data in base64 URL format. | ||
*/ | ||
private function base64UrlEncode(string $data): string { | ||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
networks: | ||
default: | ||
services: | ||
chromedriver: | ||
image: drupalci/webdriver-chromedriver:production | ||
entrypoint: | ||
- chromedriver | ||
- "--log-path=/dev/null" | ||
- "--verbose" | ||
- "--allowed-ips=" | ||
- "--allowed-origins=*" | ||
drupal: | ||
image: lehighlts/drupal-ci:${DRUPAL_VERSION}-php${PHP_VERSION} | ||
volumes: | ||
- ${MODULE_DIRECTORY}:/var/www/drupal/web/modules/contrib/${ENABLE_MODULES} | ||
environment: | ||
SIMPLETEST_BASE_URL: http://drupal:8282 | ||
ENABLE_MODULES: ${ENABLE_MODULES} | ||
MINK_DRIVER_ARGS_WEBDRIVER: '["chrome", {"browserName":"chrome","goog:chromeOptions":{"args":["--disable-gpu","--headless", "--no-sandbox", "--disable-dev-shm-usage"]}}, "http://chromedriver:9515"]' | ||
SYMFONY_DEPRECATIONS_HELPER: weak | ||
links: | ||
- chromedriver |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\Tests\islandora_jwks\Unit\Controller; | ||
|
||
use Drupal\islandora_jwks\Controller\IslandoraJwksController; | ||
use PHPUnit\Framework\TestCase; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
|
||
/** | ||
* Tests the IslandoraJwksController. | ||
* | ||
* @group islandora_jwks | ||
*/ | ||
final class IslandoraJwksControllerTest extends TestCase { | ||
|
||
/** | ||
* Tests the JWKS response. | ||
*/ | ||
public function testJwksResponse(): void { | ||
// Sample RSA public key (PEM format) | ||
$publicKey = <<<EOD | ||
-----BEGIN PUBLIC KEY----- | ||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6uK3nozywVaRCAB3FHdR | ||
ZNHunSZvN/c31QimZAqQMGxj7JrGh1LF8JRX+XAQ+CJcPD9r6xXjKSS1Gqa2Os2w | ||
ARr/9abIwG5QeNsrJ8GMt3Z/WICnNeaFAkUVviwKWcA61iFJWvTDAuI0hCaxArRK | ||
sk0BfFSMh+4u3JAdD9tUxUx6AAUXUCdtPyluaBd53wuB0r9xRlPnDw6I9QHfKK80 | ||
Xrrsu1PYATgrsy69stzCln3KlO5Oxc6O8OjMdjC2D2c3HmsO4CKPvvaVuaow/a9P | ||
a3SNje4UXN+/1xUfQskxafP8CKVSr8xxtwzSureiskb5/98moAiutpUtp15yyAm0 | ||
rwIDAQAB | ||
-----END PUBLIC KEY----- | ||
EOD; | ||
|
||
$mock = $this->getMockBuilder(IslandoraJwksController::class) | ||
->onlyMethods(['readPublicKey']) | ||
->getMock(); | ||
|
||
$mock->method('readPublicKey') | ||
->willReturn($publicKey); | ||
|
||
$response = $mock->__invoke(); | ||
|
||
$this->assertInstanceOf(JsonResponse::class, $response); | ||
|
||
$jwks = json_decode($response->getContent(), TRUE); | ||
$this->assertArrayHasKey('keys', $jwks); | ||
$this->assertCount(1, $jwks['keys']); | ||
$this->assertEquals('RSA', $jwks['keys'][0]['kty']); | ||
$this->assertEquals('RS256', $jwks['keys'][0]['alg']); | ||
$this->assertEquals('sig', $jwks['keys'][0]['use']); | ||
$this->assertEquals('df52de600a824a30ba84a4745b0ebcebf7edca44', $jwks['keys'][0]['kid']); | ||
$this->assertArrayHasKey('n', $jwks['keys'][0]); | ||
$this->assertArrayHasKey('e', $jwks['keys'][0]); | ||
} | ||
|
||
} |