Store OIDC config in cookie instead of URL

This commit is contained in:
Rory Powell 2021-07-15 16:20:31 +01:00
parent 239e39e5ed
commit 33b352c3ef
7 changed files with 35 additions and 21 deletions

View File

@ -6,6 +6,7 @@ exports.UserStatus = {
exports.Cookies = {
CurrentApp: "budibase:currentapp",
Auth: "budibase:auth",
OIDC_CONFIG: "budibase:oidc:config",
}
exports.GlobalRoles = {

View File

@ -4,7 +4,7 @@
import Auth0Logo from "assets/auth0-logo.png"
import MicrosoftLogo from "assets/microsoft-logo.png"
import { admin, oidc } from "stores/portal"
import { oidc } from "stores/portal"
import { onMount } from "svelte"
let show = false
@ -27,7 +27,8 @@
{#if show}
<ActionButton
on:click={() => window.open(`/api/admin/auth/oidc/${$oidc.uuid}`, "_blank")}
on:click={() =>
window.open(`/api/admin/auth/oidc/configs/${$oidc.uuid}`, "_blank")}
>
<div class="inner">
<img {src} alt="oidc icon" />

View File

@ -79,10 +79,6 @@
providers.oidc?.config?.configs[0].clientID &&
providers.oidc?.config?.configs[0].clientSecret
$: oidcCallback = providers.oidc?.config.configs[0].uuid
? `/api/admin/auth/oidc/callback/${providers.oidc?.config.configs[0].uuid}`
: ""
async function uploadLogo(file) {
let data = new FormData()
data.append("file", file)
@ -240,7 +236,7 @@
{/each}
<div class="form-row">
<Label size="L">Callback URL</Label>
<Input readonly bind:value={oidcCallback} />
<Input readonly placeholder="/api/admin/auth/oidc/callback" />
</div>
<br />
<Body size="S">

View File

@ -4,7 +4,8 @@ const { oidc } = require("@budibase/auth/src/middleware")
const { Configs, EmailTemplatePurpose } = require("../../../constants")
const CouchDB = require("../../../db")
const { sendEmail, isEmailConfigured } = require("../../../utilities/email")
const { clearCookie, getGlobalUserByEmail, hash } = authPkg.utils
const { setCookie, getCookie, clearCookie, getGlobalUserByEmail, hash } =
authPkg.utils
const { Cookies } = authPkg.constants
const { passport } = authPkg.auth
const { checkResetPasswordCode } = require("../../../utilities/redis")
@ -133,9 +134,7 @@ exports.googleAuth = async (ctx, next) => {
)(ctx, next)
}
async function oidcStrategyFactory(ctx) {
const { configId } = ctx.params
async function oidcStrategyFactory(ctx, configId) {
const db = new CouchDB(GLOBAL_DB)
const config = await authPkg.db.getScopedConfig(db, {
@ -145,7 +144,7 @@ async function oidcStrategyFactory(ctx) {
const chosenConfig = config.configs.filter(c => c.uuid === configId)[0]
const callbackUrl = `${ctx.protocol}://${ctx.host}/api/admin/auth/oidc/callback/${configId}`
const callbackUrl = `${ctx.protocol}://${ctx.host}/api/admin/auth/oidc/callback`
return oidc.strategyFactory(chosenConfig, callbackUrl)
}
@ -155,7 +154,10 @@ async function oidcStrategyFactory(ctx) {
* On a successful login, you will be redirected to the oidcAuth callback route.
*/
exports.oidcPreAuth = async (ctx, next) => {
const strategy = await oidcStrategyFactory(ctx)
const { configId } = ctx.params
const strategy = await oidcStrategyFactory(ctx, configId)
setCookie(ctx, configId, Cookies.OIDC_CONFIG)
return passport.authenticate(strategy, {
// required 'openid' scope is added by oidc strategy factory
@ -164,7 +166,8 @@ exports.oidcPreAuth = async (ctx, next) => {
}
exports.oidcAuth = async (ctx, next) => {
const strategy = await oidcStrategyFactory(ctx)
const configId = getCookie(ctx, Cookies.OIDC_CONFIG)
const strategy = await oidcStrategyFactory(ctx, configId)
return passport.authenticate(
strategy,

View File

@ -39,7 +39,7 @@ router
.post("/api/admin/auth/logout", authController.logout)
.get("/api/admin/auth/google", authController.googlePreAuth)
.get("/api/admin/auth/google/callback", authController.googleAuth)
.get("/api/admin/auth/oidc/:configId", authController.oidcPreAuth)
.get("/api/admin/auth/oidc/callback/:configId", authController.oidcAuth)
.get("/api/admin/auth/oidc/configs/:configId", authController.oidcPreAuth)
.get("/api/admin/auth/oidc/callback", authController.oidcAuth)
module.exports = router

View File

@ -1,4 +1,5 @@
const setup = require("./utilities")
const { Cookies } = require("@budibase/auth").constants
jest.mock("nodemailer")
const sendMailMock = setup.emailMock()
@ -74,13 +75,13 @@ describe("/api/admin/auth", () => {
afterEach(() => {
expect(strategyFactory).toBeCalledWith(
chosenConfig,
`http://127.0.0.1:4003/api/admin/auth/oidc/callback/${configId}` // calculated url
`http://127.0.0.1:4003/api/admin/auth/oidc/callback` // calculated url
)
})
describe("/api/admin/auth/oidc", () => {
describe("/api/admin/auth/oidc/configs", () => {
it("should load strategy and delegate to passport", async () => {
await request.get(`/api/admin/auth/oidc/${configId}`)
await request.get(`/api/admin/auth/oidc/configs/${configId}`)
expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
scope: ["profile", "email"],
@ -91,7 +92,8 @@ describe("/api/admin/auth", () => {
describe("/api/admin/auth/oidc/callback", () => {
it("should load strategy and delegate to passport", async () => {
await request.get(`/api/admin/auth/oidc/callback/${configId}`)
await request.get(`/api/admin/auth/oidc/callback`)
.set(config.getOIDConfigCookie(configId))
expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
successRedirect: "/", failureRedirect: "/error"

View File

@ -68,6 +68,12 @@ class TestConfiguration {
}
}
cookieHeader(cookies) {
return {
Cookie: [cookies],
}
}
defaultHeaders() {
const user = {
_id: "us_uuid1",
@ -77,7 +83,7 @@ class TestConfiguration {
const authToken = jwt.sign(user, env.JWT_SECRET)
return {
Accept: "application/json",
Cookie: [`${Cookies.Auth}=${authToken}`],
...this.cookieHeader([`${Cookies.Auth}=${authToken}`]),
}
}
@ -156,6 +162,11 @@ class TestConfiguration {
)
}
getOIDConfigCookie(configId) {
const token = jwt.sign(configId, env.JWT_SECRET)
return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]])
}
async saveOIDCConfig() {
await this.deleteConfig(Configs.OIDC)
const config = {