-
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.
m-ld/sustainable-web-apps#7: Using KeyCloak for application login
Note: requires m-ld/m-ld-gateway#10
- Loading branch information
1 parent
faa04a5
commit ee1799e
Showing
10 changed files
with
3,575 additions
and
26 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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
node_modules | ||
.DS_Store | ||
.idea | ||
.vercel | ||
.env*.local |
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,60 @@ | ||
import {createRemoteJWKSet, jwtVerify} from "jose"; | ||
import request from "needle"; | ||
|
||
const {AUTH_SERVER_URL, AUTH_REALM, GATEWAY_ACCOUNT_URL, GATEWAY_KEY} = process.env; | ||
// Credit: https://github.com/keycloak/keycloak-nodejs-connect/issues/492#issuecomment-1603213677 | ||
const jwks = createRemoteJWKSet(new URL( | ||
`${AUTH_SERVER_URL}/realms/${AUTH_REALM}/protocol/openid-connect/certs`)); | ||
const GATEWAY = new class { | ||
accountUrl = new URL(GATEWAY_ACCOUNT_URL); | ||
accountName = this.accountUrl.pathname.slice(1); | ||
}; | ||
|
||
// noinspection JSUnusedGlobalSymbols | ||
/** | ||
* @param {import('@vercel/node').VercelRequest} req | ||
* @param {import('@vercel/node').VercelResponse} res | ||
*/ | ||
export default async function (req, res) { | ||
const sendErr = (code, text, error) => { | ||
console.warn(error); | ||
res.status(code).json({text, error}); | ||
}; | ||
const throwErr = (code, text) => error => { | ||
throw {send: () => sendErr(code, text, error)}; | ||
}; | ||
try { | ||
const subdomain = req.query.domain; | ||
const [type, token] = req.headers.authorization?.split(" ") ?? []; | ||
if (type !== "Bearer") | ||
return sendErr(401, 'Unauthorised'); | ||
const {payload} = await jwtVerify(token, jwks) | ||
.catch(throwErr(401, 'Unauthorised')); | ||
await checkAccess(payload.sub, subdomain) | ||
.catch(throwErr(403, 'Forbidden')); | ||
const configRes = await request('put', new URL( | ||
`/api/v1/domain/${GATEWAY.accountName}/${subdomain}`, GATEWAY.accountUrl | ||
).toString(), { | ||
user: {'@id': `${AUTH_SERVER_URL}/users/${payload.sub}`} | ||
}, { | ||
json: true, | ||
auth: 'basic', | ||
username: GATEWAY.accountName, | ||
password: GATEWAY_KEY | ||
}); | ||
if (configRes.statusCode !== 200) | ||
return sendErr(configRes.statusCode, configRes.statusMessage, configRes.body); | ||
res.status(200).json(configRes.body); | ||
} catch (error) { | ||
error.send ? error.send() : sendErr(500, 'Internal Server Error', error); | ||
} | ||
} | ||
|
||
/** | ||
* Check whether the given user has access to the given todolist (domain) | ||
* @param {string} user the authenticated user according to the identity provider | ||
* @param {string} subdomain the todolist identity | ||
*/ | ||
async function checkAccess(user, subdomain) { | ||
// TODO: Check fine-grained access to todolists, via sharing | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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
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
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
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,38 @@ | ||
@startuml | ||
'https://plantuml.com/sequence-diagram | ||
|
||
autonumber | ||
|
||
participant "App\nClient" as appC | ||
participant "Identity\nProvider" as idp | ||
participant "App\nLambda" as appL | ||
participant "**m-ld**\nGateway" as gw | ||
|
||
activate appC | ||
alt not logged in | ||
appC -> idp ++ : login | ||
return appToken | ||
alt new device | ||
appC -> appC : generate device key | ||
end | ||
end | ||
|
||
appC -> appL ++ : get GW token (appToken, publicKey, domainName) | ||
appL -> appL : validate appToken | ||
appL -> appL : check access | ||
appL -> gw ++ : get config\n(publicKey, domainName) | ||
note right: also ensures user is\nin domain, if required | ||
return config | ||
return config | ||
|
||
appC -> gw : connect to domain (config) | ||
deactivate appC | ||
|
||
loop | ||
appC -> appC : sign operation (privateKey) | ||
appC --> gw : operation //via domain remotes// | ||
gw -> gw : validate operation (publicKey) | ||
gw -> gw : log operation | ||
end | ||
|
||
@enduml |
Oops, something went wrong.