feat(xo-server-auth-oidc): OpenID Connect authentication plugin (#6684)
Fixes #6627
This commit is contained in:
parent
3bbb828284
commit
949a4697fe
@ -9,6 +9,7 @@
|
||||
|
||||
- [VM/Advanced] Warning message when enabling Windows update tools [#6627](https://github.com/vatesfr/xen-orchestra/issues/6627) (PR [#6681](https://github.com/vatesfr/xen-orchestra/issues/6681))
|
||||
- [Continuous Replication] : add HealthCheck support to Continuous Replication (PR [#6668](https://github.com/vatesfr/xen-orchestra/pull/6668))
|
||||
- [Plugin/auth-oidc] [OpenID Connect](<https://en.wikipedia.org/wiki/OpenID#OpenID_Connect_(OIDC)>) authentication plugin [#6641](https://github.com/vatesfr/xen-orchestra/issues/6641) (PR [#6684](https://github.com/vatesfr/xen-orchestra/issues/6684))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
@ -37,6 +38,7 @@
|
||||
- @xen-orchestra/backups minor
|
||||
- xen-api patch
|
||||
- xo-cli minor
|
||||
- xo-server-auth-oidc minor
|
||||
- xo-web minor
|
||||
- xo-server patch
|
||||
|
||||
|
11
packages/xo-server-auth-oidc/.USAGE.md
Normal file
11
packages/xo-server-auth-oidc/.USAGE.md
Normal file
@ -0,0 +1,11 @@
|
||||
This plugin allows users to authenticate to Xen-Orchestra using [OpenID Connect](<https://en.wikipedia.org/wiki/OpenID#OpenID_Connect_(OIDC)>).
|
||||
|
||||
The first time a user signs in, XO will create a new XO user with the
|
||||
same identifier.
|
||||
|
||||
Like all other xo-server plugins, it can be configured directly via
|
||||
the web interface, see [the plugin documentation](https://xen-orchestra.com/docs/plugins.html).
|
||||
|
||||
> Important: When registering your instance to your identity provider,
|
||||
> you must configure its callback URL to
|
||||
> `http://xo.company.net/signin/oidc/callback`!
|
1
packages/xo-server-auth-oidc/.npmignore
Symbolic link
1
packages/xo-server-auth-oidc/.npmignore
Symbolic link
@ -0,0 +1 @@
|
||||
../../scripts/npmignore
|
32
packages/xo-server-auth-oidc/README.md
Normal file
32
packages/xo-server-auth-oidc/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
<!-- DO NOT EDIT MANUALLY, THIS FILE HAS BEEN GENERATED -->
|
||||
|
||||
# xo-server-auth-oidc
|
||||
|
||||
## Usage
|
||||
|
||||
This plugin allows users to authenticate to Xen-Orchestra using [OpenID Connect](<https://en.wikipedia.org/wiki/OpenID#OpenID_Connect_(OIDC)>).
|
||||
|
||||
The first time a user signs in, XO will create a new XO user with the
|
||||
same identifier.
|
||||
|
||||
Like all other xo-server plugins, it can be configured directly via
|
||||
the web interface, see [the plugin documentation](https://xen-orchestra.com/docs/plugins.html).
|
||||
|
||||
> Important: When registering your instance to your identity provider,
|
||||
> you must configure its callback URL to
|
||||
> `http://xo.company.net/signin/oidc/callback`!
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are _very_ welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
[AGPL-3.0-or-later](https://spdx.org/licenses/AGPL-3.0-or-later) © [Vates SAS](https://vates.fr)
|
101
packages/xo-server-auth-oidc/index.js
Normal file
101
packages/xo-server-auth-oidc/index.js
Normal file
@ -0,0 +1,101 @@
|
||||
'use strict'
|
||||
|
||||
const { Strategy } = require('passport-openidconnect')
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const DISCOVERABLE_SETTINGS = ['authorizationURL', 'issuer', 'userInfoURL', 'tokenURL']
|
||||
|
||||
exports.configurationSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
discoveryURL: {
|
||||
description: 'If this field is not used, you will need to manually enter settings in the *Advanced* section.',
|
||||
title: 'Auto-discovery URL',
|
||||
type: 'string',
|
||||
},
|
||||
clientID: { title: 'Client identifier (key)', type: 'string' },
|
||||
clientSecret: { title: 'Client secret', type: 'string' },
|
||||
|
||||
advanced: {
|
||||
title: 'Advanced',
|
||||
type: 'object',
|
||||
properties: {
|
||||
authorizationURL: { title: 'Authorization URL', type: 'string' },
|
||||
callbackURL: {
|
||||
description: 'Default to https://<xo.company.net>/signin/oidc/callback`.',
|
||||
title: 'Callback URL',
|
||||
type: 'string',
|
||||
},
|
||||
issuer: { title: 'Issuer', type: 'string' },
|
||||
tokenURL: { title: 'Token URL', type: 'string' },
|
||||
userInfoURL: { title: 'User info URL', type: 'string' },
|
||||
usernameField: {
|
||||
default: 'username',
|
||||
description: 'Field to use as the XO username',
|
||||
title: 'Username field',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['clientID', 'clientSecret'],
|
||||
anyOf: [{ required: ['discoveryURL'] }, { properties: { advanced: { required: DISCOVERABLE_SETTINGS } } }],
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class AuthOidc {
|
||||
#conf
|
||||
#unregisterPassportStrategy
|
||||
#xo
|
||||
|
||||
constructor(xo) {
|
||||
this.#xo = xo
|
||||
}
|
||||
|
||||
async configure({ advanced, ...conf }, { loaded }) {
|
||||
this.#conf = { callbackURL: '/signin/oidc/callback', ...advanced, ...conf }
|
||||
|
||||
if (loaded) {
|
||||
await this.unload()
|
||||
await this.load()
|
||||
}
|
||||
}
|
||||
|
||||
async load() {
|
||||
const xo = this.#xo
|
||||
const { discoveryURL, usernameField, ...conf } = this.#conf
|
||||
|
||||
if (discoveryURL !== undefined) {
|
||||
const res = await this.#xo.httpRequest(discoveryURL)
|
||||
const data = await res.json()
|
||||
|
||||
for (const key of DISCOVERABLE_SETTINGS) {
|
||||
if (!conf[key]) {
|
||||
conf[key] = data[key.endsWith('URL') ? key.slice(0, -3).toLowerCase() + '_endpoint' : key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.#unregisterPassportStrategy = xo.registerPassportStrategy(
|
||||
new Strategy(conf, async (issuer, profile, done) => {
|
||||
try {
|
||||
const { id, [usernameField]: name } = profile
|
||||
done(null, await xo.registerUser2('oidc:' + issuer, { user: { id, name } }))
|
||||
} catch (error) {
|
||||
done(error.message)
|
||||
}
|
||||
}),
|
||||
{ label: 'OpenID Connect', name: 'oidc' }
|
||||
)
|
||||
}
|
||||
|
||||
unload() {
|
||||
this.#unregisterPassportStrategy()
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
exports.default = ({ xo }) => new AuthOidc(xo)
|
23
packages/xo-server-auth-oidc/package.json
Normal file
23
packages/xo-server-auth-oidc/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "xo-server-auth-oidc",
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/packages/xo-server-auth-oidc",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"directory": "packages/xo-server-auth-oidc",
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Vates SAS",
|
||||
"url": "https://vates.fr"
|
||||
},
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"version": "0.0.0",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"passport-openidconnect": "^0.1.1"
|
||||
}
|
||||
}
|
@ -15061,6 +15061,14 @@ passport-oauth2@1.x.x:
|
||||
uid2 "0.0.x"
|
||||
utils-merge "1.x.x"
|
||||
|
||||
passport-openidconnect@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/passport-openidconnect/-/passport-openidconnect-0.1.1.tgz#83921ff5f87f634079f65262dada834af1972244"
|
||||
integrity sha512-r0QJiWEzwCg2MeCIXVP5G6YxVRqnEsZ2HpgKRthZ9AiQHJrgGUytXpsdcGF9BRwd3yMrEesb/uG/Yxb86rrY0g==
|
||||
dependencies:
|
||||
oauth "0.9.x"
|
||||
passport-strategy "1.x.x"
|
||||
|
||||
passport-saml@^3.2.0:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/passport-saml/-/passport-saml-3.2.4.tgz#e8e9523f954988a3a47d12e425d7fa0f20a74dc9"
|
||||
|
Loading…
Reference in New Issue
Block a user