Verified Commit 07fa3d9a authored by Chocobozzz's avatar Chocobozzz
Browse files

Fix SAML signature

parent 147538fa
# SAML2 auth plugin for PeerTube
Add SAML2 support to login form in PeerTube.
## Keycloak example
### Signature
If you want to sign get requests:
* Generate a certificate and private key: `openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem`
* Import `cert.pem` in keycloak SAML client
* Copy `cert.pem` and `key.pem` in PeerTube SAML plugin settings
* Check the *Sign get request* checkbox in PeerTube SAML plugin settings
### Provider certificate
You can find the public key on: `http://keycloak.example.com/auth/realms/{realm}/protocol/saml/descriptor`.
......@@ -29,14 +29,6 @@ async function register ({
default: metadataUrl
})
registerSetting({
name: 'sign-get-request',
label: 'Sign get request',
type: 'input-checkbox',
private: true,
default: false
})
registerSetting({
name: 'auth-display-name',
label: 'Auth display name',
......@@ -54,11 +46,33 @@ async function register ({
registerSetting({
name: 'provider-certificate',
label: 'Identity provider certificate',
label: 'Identity provider certificate (PEM format)',
type: 'input-textarea',
private: true
})
registerSetting({
name: 'service-certificate',
label: 'Service certificate (PEM format)',
type: 'input-textarea',
private: true
})
registerSetting({
name: 'service-private-key',
label: 'Service private key (PEM format)',
type: 'input-textarea',
private: true
})
registerSetting({
name: 'sign-get-request',
label: 'Sign get request',
type: 'input-checkbox',
private: true,
default: false
})
registerSetting({
name: 'username-property',
label: 'Username property',
......@@ -145,7 +159,9 @@ async function loadSettingsAndCreateProviders (
'client-id',
'sign-get-request',
'login-url',
'provider-certificate'
'provider-certificate',
'service-certificate',
'service-private-key'
])
if (!settings['login-url']) {
......@@ -158,12 +174,12 @@ async function loadSettingsAndCreateProviders (
return
}
const { publicKey: servicePublicKey, privateKey: servicePrivateKey } = await lazyLoadServiceCertificates(peertubeHelpers, storageManager)
logger.debug('Creating SAML service/identity instances.', { settings })
const serviceOptions = {
entity_id: settings['client-id'],
private_key: servicePrivateKey,
certificate: servicePublicKey,
private_key: settings['service-private-key'],
certificate: settings['service-certificate'],
assert_endpoint: store.assertUrl
}
store.serviceProvider = new saml2.ServiceProvider(serviceOptions)
......@@ -182,14 +198,19 @@ async function loadSettingsAndCreateProviders (
authName: 'saml2',
authDisplayName: () => store.authDisplayName,
onAuthRequest: async (req, res) => {
store.serviceProvider.create_login_request_url(store.identityProvider, {}, (err, loginUrl, requestId) => {
if (err) {
logger.error('Cannot SAML 2 authenticate.', { err })
return redirectOnError(res)
}
res.redirect(loginUrl)
})
try {
store.serviceProvider.create_login_request_url(store.identityProvider, {}, (err, loginUrl, requestId) => {
if (err) {
logger.error('Cannot SAML 2 authenticate.', { err })
return redirectOnError(res)
}
res.redirect(loginUrl)
})
} catch (err) {
logger.error('Cannot create login request url.', { err })
return redirectOnError(res)
}
}
})
......@@ -256,39 +277,3 @@ async function buildUser (settingsManager, samlUser) {
role: findInUser(samlUser, settings['role-property'])
}
}
async function lazyLoadServiceCertificates (peertubeHelpers, storageManager) {
const { logger } = peertubeHelpers
let privateKey = await storageManager.getData('service-private-key')
let publicKey = await storageManager.getData('service-public-key')
if (!privateKey || !publicKey) {
logger.info('Generating public/private keys for SAML 2.')
return new Promise((res, rej) => {
const options = {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
}
crypto.generateKeyPair('rsa', options, (err, publicKey, privateKey) => {
if (err) return rej(err)
Promise.all([
storageManager.storeData('service-private-key', privateKey),
storageManager.storeData('service-public-key', publicKey)
]).then(() => res({ publicKey, privateKey }))
})
})
}
return { privateKey, publicKey }
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment