Skip to content

Commit

Permalink
Merge pull request #3189 from Opetushallitus/tor-2210-oauth2-metadata…
Browse files Browse the repository at this point in the history
…-route

TOR-2210 OmaData OAuth2 metadata route ja ensimmäinen versio rajapinnan dokumentaatiosta
  • Loading branch information
AleksiAhtiainen authored Nov 1, 2024
2 parents cb70252 + 70eac28 commit 8862b30
Show file tree
Hide file tree
Showing 19 changed files with 496 additions and 99 deletions.
2 changes: 1 addition & 1 deletion omadata-oauth2-sample/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"start-react-scripts": "react-scripts start",
"start-with-server": "npm-run-all --parallel start-server start",
"start-with-server-and-luovutuspalvelu": "npm-run-all --parallel build-and-start-luovutuspalvelu start-server start",
"start-server": "NODE_EXTRA_CA_CERTS=../../koski-luovutuspalvelu/proxy/test/testca/certs/root-ca.crt CLIENT_ID=omadataoauth2sample ENABLE_LOCAL_MTLS=true TOKEN_ENDPOINT_URL=https://localhost:7022/koski/api/omadata-oauth2/authorization-server RESOURCE_ENDPOINT_URL=https://localhost:7022/koski/api/omadata-oauth2/resource-server npm run --prefix ../server start",
"start-server": "NODE_EXTRA_CA_CERTS=../../koski-luovutuspalvelu/proxy/test/testca/certs/root-ca.crt CLIENT_ID=omadataoauth2sample ENABLE_LOCAL_MTLS=true RESOURCE_ENDPOINT_URL=https://localhost:7022/koski/api/omadata-oauth2/resource-server npm run --prefix ../server start",
"build-and-start-luovutuspalvelu": "KOSKI_BACKEND_HOST=${KOSKI_BACKEND_HOST:-http://$(node scripts/getmyip.js):7021} CLIENT_USERNAME='omadataoauth2sample' CLIENT_PASSWORD='omadataoauth2sample' npm run --prefix ../../koski-luovutuspalvelu/proxy local",
"build": "react-scripts build",
"test": "react-scripts test",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ test("Standard error from server is displayed when user declines", async ({

// Check that error data is displayed
await page.waitForURL("**/api/openid-api-test/form-post-response-cb**")
await expect(page.locator("html")).toContainText(
'{"state":"state-placeholder","error":"access_denied"}',
)
await expect(page.locator("html")).toContainText('"error":"access_denied"')
})

test("Error page displayed in browser when using invalid redirect_uri", async ({
Expand Down
37 changes: 32 additions & 5 deletions omadata-oauth2-sample/server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion omadata-oauth2-sample/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"express-rate-limit": "^7.4.0",
"helmet": "^7.1.0",
"openid-client": "^6.1.1",
"undici": "^6.20.1"
"undici": "^6.20.1",
"uuid": "^11.0.2"
},
"devDependencies": {
"@aws-sdk/types": "^3.654.0",
Expand Down
25 changes: 21 additions & 4 deletions omadata-oauth2-sample/server/src/apiroutes/openid-api-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import express, { NextFunction, Request, Response, Router } from 'express'
import * as client from 'openid-client'
import { v4 as uuidv4 } from 'uuid'
import {
buildAuthorizationUrl,
fetchAccessToken,
Expand All @@ -10,18 +11,23 @@ import {
ClientError,
ResponseBodyError
} from 'openid-client'
import { URLSearchParams } from 'url'

const router: Router = express.Router()

const code_verifier: string = client.randomPKCECodeVerifier()
const state = 'state-placeholder'
// TODO: TOR-2210: Toistaiseksi vain muistinvarainen map
let verifiers: Map<string, string> = new Map()

const scope: string =
'HENKILOTIEDOT_NIMI HENKILOTIEDOT_SYNTYMAAIKA HENKILOTIEDOT_HETU OPISKELUOIKEUDET_SUORITETUT_TUTKINNOT'

router.get('/', async (req: Request, res: Response, next: NextFunction) => {
try {
let redirectTo = await buildAuthorizationUrl(code_verifier, state, scope)
const state = uuidv4()
const code_verifier = client.randomPKCECodeVerifier()
verifiers.set(state, code_verifier)

const redirectTo = await buildAuthorizationUrl(code_verifier, state, scope)

res.redirect(redirectTo.href)
} catch (err) {
Expand All @@ -33,7 +39,10 @@ router.get(
'/invalid-redirect-uri',
async (req: Request, res: Response, next: NextFunction) => {
try {
let redirectTo = await buildAuthorizationUrl(
const state = uuidv4()
const code_verifier = client.randomPKCECodeVerifier()

const redirectTo = await buildAuthorizationUrl(
code_verifier,
state,
scope,
Expand All @@ -56,6 +65,14 @@ router.post(
'/form-post-response-cb',
async (req: Request, res: Response, next: NextFunction) => {
try {
const params = new URLSearchParams(req.body)
const state = params.get('state') || ''
const code_verifier = (state && verifiers.get(state)) || ''

if (state) {
verifiers.delete(state)
}

const token = await fetchAccessToken(req, code_verifier, state)

const protectedResource = await fetchData(token)
Expand Down
72 changes: 0 additions & 72 deletions omadata-oauth2-sample/server/src/config/oauth-client-config.ts

This file was deleted.

50 changes: 50 additions & 0 deletions omadata-oauth2-sample/server/src/config/oauth2-client-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as client from 'openid-client'
import { Configuration } from 'openid-client'
import { memoize } from '../util/memoize.js'
import { enableLocalMTLS, getClientCertSecret } from './client-cert-config.js'
import * as undici from 'undici'
import { koskiBackendHost } from './koski-backend-config.js'

const clientId = process.env.CLIENT_ID || 'oauth2client'
const clientMetadata: client.ClientMetadata = {
client_id: clientId,
use_mtls_endpoint_aliases: false
}
export const getOAuthClientConfig = memoize(
async (): Promise<Configuration> => {
const discoveryOptions = enableLocalMTLS
? {
execute: [client.allowInsecureRequests]
}
: undefined

let config = await client.discovery(
new URL(
`${koskiBackendHost}/koski/omadata-oauth2/.well-known/oauth-authorization-server`
),
clientId,
clientMetadata,
client.TlsClientAuth(),
discoveryOptions
)

const certs = await getClientCertSecret()

const options = {
cert: certs['fullchain.pem'],
key: certs['privkey.pem']
}

const agent = new undici.Agent({ connect: options })
config[client.customFetch] = (...args) =>
// @ts-expect-error
undici.fetch(args[0], { ...args[1], dispatcher: agent })

if (enableLocalMTLS) {
client.allowInsecureRequests(config)
}

return config
},
() => 'oauthClientConfig'
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getOAuthClientConfig } from '../config/oauth-client-config.js'
import { getOAuthClientConfig } from '../config/oauth2-client-config.js'
import * as client from 'openid-client'
import { resourceEndpointUrl } from '../config/koski-backend-config.js'
import { Request } from 'express'
Expand Down
Loading

0 comments on commit 8862b30

Please sign in to comment.