snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
37
packages/cas-validate/CHANGELOG.md
Normal file
37
packages/cas-validate/CHANGELOG.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# @rocket.chat/cas-validate
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#38989](https://github.com/RocketChat/Rocket.Chat/pull/38989)) chore(eslint): Upgrades ESLint and its configuration
|
||||
|
||||
## 0.0.4-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#38989](https://github.com/RocketChat/Rocket.Chat/pull/38989)) chore(eslint): Upgrades ESLint and its configuration
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#35115](https://github.com/RocketChat/Rocket.Chat/pull/35115) by [@tapiarafael](https://github.com/tapiarafael)) Fixes a problem with CAS when URL connection ended with `/`
|
||||
|
||||
## 0.0.3-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#35115](https://github.com/RocketChat/Rocket.Chat/pull/35115)) Fixes a problem with CAS when URL connection ended with `/`
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#31138](https://github.com/RocketChat/Rocket.Chat/pull/31138)) feat(uikit): Move `@rocket.chat/ui-kit` package to the main monorepo
|
||||
|
||||
## 0.0.2-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b223cbde14: feat(uikit): Move `@rocket.chat/ui-kit` package to the main monorepo
|
||||
12
packages/cas-validate/jest.config.ts
Normal file
12
packages/cas-validate/jest.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import server from '@rocket.chat/jest-presets/server';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
export default {
|
||||
projects: [
|
||||
{
|
||||
displayName: 'server',
|
||||
preset: server.preset,
|
||||
testMatch: ['<rootDir>/src/**/*.spec.[jt]s?(x)'],
|
||||
},
|
||||
],
|
||||
} satisfies Config;
|
||||
29
packages/cas-validate/package.json
Normal file
29
packages/cas-validate/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@rocket.chat/cas-validate",
|
||||
"version": "0.0.4",
|
||||
"private": true,
|
||||
"description": "Fork of https://github.com/kcbanner/node-cas",
|
||||
"main": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"/dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsc -p tsconfig.json",
|
||||
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"testunit": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "~9.39.5",
|
||||
"jest": "~30.2.0",
|
||||
"typescript": "~5.9.3"
|
||||
},
|
||||
"volta": {
|
||||
"extends": "../../package.json"
|
||||
}
|
||||
}
|
||||
1
packages/cas-validate/src/index.ts
Normal file
1
packages/cas-validate/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './validate';
|
||||
53
packages/cas-validate/src/validate.spec.ts
Normal file
53
packages/cas-validate/src/validate.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { getQueryPath } from './validate';
|
||||
|
||||
describe('getQueryPath', () => {
|
||||
it('should generate the correct query path without trailing slash', () => {
|
||||
const partialPathname = '/cas';
|
||||
const validatePath = 'validate';
|
||||
const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
|
||||
|
||||
const result = getQueryPath(partialPathname, validatePath, query);
|
||||
|
||||
expect(result).toBe('/cas/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
|
||||
});
|
||||
|
||||
it('should generate the correct query path with trailing slash', () => {
|
||||
const partialPathname = '/cas/';
|
||||
const validatePath = 'validate';
|
||||
const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
|
||||
|
||||
const result = getQueryPath(partialPathname, validatePath, query);
|
||||
|
||||
expect(result).toBe('/cas/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
|
||||
});
|
||||
|
||||
it('should generate the correct query path with `/` partialPathname', () => {
|
||||
const partialPathname = '/';
|
||||
const validatePath = 'validate';
|
||||
const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
|
||||
|
||||
const result = getQueryPath(partialPathname, validatePath, query);
|
||||
|
||||
expect(result).toBe('/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
|
||||
});
|
||||
|
||||
it('should generate the correct query path with empty partialPathname', () => {
|
||||
const partialPathname = '';
|
||||
const validatePath = 'validate';
|
||||
const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
|
||||
|
||||
const result = getQueryPath(partialPathname, validatePath, query);
|
||||
|
||||
expect(result).toBe('/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
|
||||
});
|
||||
|
||||
it('should generate the correct query path with empty query', () => {
|
||||
const partialPathname = '/cas';
|
||||
const validatePath = 'validate';
|
||||
const query = {};
|
||||
|
||||
const result = getQueryPath(partialPathname, validatePath, query);
|
||||
|
||||
expect(result).toBe('/cas/validate');
|
||||
});
|
||||
});
|
||||
299
packages/cas-validate/src/validate.ts
Normal file
299
packages/cas-validate/src/validate.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
import type { IncomingMessage } from 'node:http';
|
||||
import https from 'node:https';
|
||||
import type { ParsedUrlQueryInput } from 'node:querystring';
|
||||
import url from 'node:url';
|
||||
|
||||
import type { Cheerio, CheerioAPI } from 'cheerio';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
export type CasOptions = {
|
||||
base_url: string;
|
||||
service?: string;
|
||||
version: 1.0 | 2.0;
|
||||
};
|
||||
|
||||
export type CasCallbackExtendedData = {
|
||||
username?: string;
|
||||
attributes?: Record<string, string[]>;
|
||||
|
||||
PGTIOU?: string;
|
||||
ticket?: string;
|
||||
proxies?: string[];
|
||||
};
|
||||
|
||||
export type CasCallback = (err: any, status?: unknown, username?: string, extended?: CasCallbackExtendedData) => void;
|
||||
|
||||
function parseJasigAttributes(elemAttribute: Cheerio<any>, cheerio: CheerioAPI): Record<string, string[]> {
|
||||
// "Jasig Style" Attributes:
|
||||
//
|
||||
// <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
|
||||
// <cas:authenticationSuccess>
|
||||
// <cas:user>jsmith</cas:user>
|
||||
// <cas:attributes>
|
||||
// <cas:attraStyle>RubyCAS</cas:attraStyle>
|
||||
// <cas:surname>Smith</cas:surname>
|
||||
// <cas:givenName>John</cas:givenName>
|
||||
// <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
|
||||
// <cas:memberOf>CN=Spanish Department,OU=Departments,...</cas:memberOf>
|
||||
// </cas:attributes>
|
||||
// <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2...</cas:proxyGrantingTicket>
|
||||
// </cas:authenticationSuccess>
|
||||
// </cas:serviceResponse>
|
||||
|
||||
const attributes: Record<string, string[]> = {};
|
||||
for (let i = 0; i < elemAttribute.children().length; i++) {
|
||||
const node = elemAttribute.children()[i];
|
||||
const attrName = node.name.toLowerCase().replace(/cas:/, '');
|
||||
if (attrName !== '#text') {
|
||||
const attrValue = cheerio(node).text();
|
||||
if (!attributes[attrName]) {
|
||||
attributes[attrName] = [attrValue];
|
||||
} else {
|
||||
attributes[attrName].push(attrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
function parseRubyCasAttributes(elemSuccess: Cheerio<any>, cheerio: CheerioAPI): Record<string, string[]> {
|
||||
// "RubyCAS Style" attributes
|
||||
//
|
||||
// <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
|
||||
// <cas:authenticationSuccess>
|
||||
// <cas:user>jsmith</cas:user>
|
||||
//
|
||||
// <cas:attraStyle>RubyCAS</cas:attraStyle>
|
||||
// <cas:surname>Smith</cas:surname>
|
||||
// <cas:givenName>John</cas:givenName>
|
||||
// <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
|
||||
// <cas:memberOf>CN=Spanish Department,OU=Departments,...</cas:memberOf>
|
||||
//
|
||||
// <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2...</cas:proxyGrantingTicket>
|
||||
// </cas:authenticationSuccess>
|
||||
// </cas:serviceResponse>
|
||||
|
||||
const attributes: Record<string, string[]> = {};
|
||||
for (let i = 0; i < elemSuccess.children().length; i++) {
|
||||
const node = elemSuccess.children()[i];
|
||||
const tagName = node.name.toLowerCase().replace(/cas:/, '');
|
||||
switch (tagName) {
|
||||
case 'user':
|
||||
case 'proxies':
|
||||
case 'proxygrantingticket':
|
||||
case '#text':
|
||||
// these are not CAS attributes
|
||||
break;
|
||||
default:
|
||||
const attrName = tagName;
|
||||
const attrValue = cheerio(node).text();
|
||||
if (attrValue !== '') {
|
||||
if (!attributes[attrName]) {
|
||||
attributes[attrName] = [attrValue];
|
||||
} else {
|
||||
attributes[attrName].push(attrValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
function parseAttributes(elemSuccess: Cheerio<any>, cheerio: CheerioAPI): Record<string, string[]> {
|
||||
const elemAttribute = elemSuccess.find('cas\\:attributes').first();
|
||||
const isJasig = elemAttribute?.children().length > 0;
|
||||
const attributes = isJasig ? parseJasigAttributes(elemAttribute, cheerio) : parseRubyCasAttributes(elemSuccess, cheerio);
|
||||
|
||||
if (Object.keys(attributes).length > 0) {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// "Name-Value" attributes.
|
||||
//
|
||||
// Attribute format from this mailing list thread:
|
||||
// http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html
|
||||
// Note: This is a less widely used format, but in use by at least two institutions.
|
||||
//
|
||||
// <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
|
||||
// <cas:authenticationSuccess>
|
||||
// <cas:user>jsmith</cas:user>
|
||||
//
|
||||
// <cas:attribute name='attraStyle' value='Name-Value' />
|
||||
// <cas:attribute name='surname' value='Smith' />
|
||||
// <cas:attribute name='givenName' value='John' />
|
||||
// <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />
|
||||
// <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,...' />
|
||||
//
|
||||
// <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
|
||||
// </cas:authenticationSuccess>
|
||||
// </cas:serviceResponse>
|
||||
//
|
||||
const nodes = elemSuccess.find('cas\\:attribute');
|
||||
if (nodes?.length) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
const attrName = node.attribs.name;
|
||||
const attrValue = node.attribs.value;
|
||||
|
||||
if (!attributes[attrName]) {
|
||||
attributes[attrName] = [attrValue];
|
||||
} else {
|
||||
attributes[attrName].push(attrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
export function getQueryPath(
|
||||
partialPathname: string,
|
||||
validatePath: string,
|
||||
query: string | ParsedUrlQueryInput | null | undefined,
|
||||
): string {
|
||||
const pathname = partialPathname?.endsWith('/') ? partialPathname + validatePath : `${partialPathname}/${validatePath}`;
|
||||
|
||||
return url.format({
|
||||
pathname,
|
||||
query,
|
||||
});
|
||||
}
|
||||
|
||||
export function validate(options: CasOptions, ticket: string, callback: CasCallback, renew = false): void {
|
||||
if (!options.base_url) {
|
||||
throw new Error('Required CAS option `base_url` missing.');
|
||||
}
|
||||
|
||||
const casUrl = url.parse(options.base_url);
|
||||
if (casUrl.protocol !== 'https:') {
|
||||
throw new Error('Only https CAS servers are supported.');
|
||||
}
|
||||
|
||||
if (!casUrl.hostname) {
|
||||
throw new Error('Option `base_url` must be a valid url like: https://example.com/cas');
|
||||
}
|
||||
const { service, version = 1.0 } = options;
|
||||
if (!service) {
|
||||
throw new Error('Required CAS option `service` missing.');
|
||||
}
|
||||
|
||||
const { hostname, port = '443', pathname = '' } = casUrl;
|
||||
const validatePath = version < 2.0 ? 'validate' : 'proxyValidate';
|
||||
|
||||
const query = {
|
||||
ticket,
|
||||
service,
|
||||
...(renew ? { renew: 1 } : {}),
|
||||
};
|
||||
|
||||
const queryPath = getQueryPath(pathname ?? '/', validatePath, query);
|
||||
|
||||
const req = https.get(
|
||||
{
|
||||
host: hostname,
|
||||
port,
|
||||
path: queryPath,
|
||||
rejectUnauthorized: true,
|
||||
},
|
||||
function (res: IncomingMessage) {
|
||||
// Handle server errors
|
||||
res.on('error', function (e) {
|
||||
callback(e);
|
||||
});
|
||||
|
||||
// Read result
|
||||
res.setEncoding('utf8');
|
||||
let response = '';
|
||||
res.on('data', function (chunk) {
|
||||
response += chunk;
|
||||
if (response.length > 1e6) {
|
||||
req.connection?.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
res.on('end', function () {
|
||||
if (version < 2.0) {
|
||||
const sections = response.split('\n');
|
||||
if (sections.length >= 1) {
|
||||
switch (sections[0]) {
|
||||
case 'no':
|
||||
return callback(undefined, false);
|
||||
case 'yes':
|
||||
if (sections.length >= 2) {
|
||||
return callback(undefined, true, sections[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return callback(new Error('Bad response format.'));
|
||||
}
|
||||
|
||||
// Use cheerio to parse the XML repsonse.
|
||||
const cheerio = load(response);
|
||||
|
||||
// Check for auth success
|
||||
const elemSuccess = cheerio('cas\\:authenticationSuccess').first();
|
||||
if (elemSuccess && elemSuccess.length > 0) {
|
||||
const elemUser = elemSuccess.find('cas\\:user').first();
|
||||
if (!elemUser || elemUser.length < 1) {
|
||||
// This should never happen
|
||||
callback(new Error('No username?'), false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Got username
|
||||
const username = elemUser.text();
|
||||
|
||||
// Look for optional proxy granting ticket
|
||||
let pgtIOU;
|
||||
const elemPGT = elemSuccess.find('cas\\:proxyGrantingTicket').first();
|
||||
if (elemPGT) {
|
||||
pgtIOU = elemPGT.text();
|
||||
}
|
||||
|
||||
// Look for optional proxies
|
||||
const proxies = [];
|
||||
const elemProxies = elemSuccess.find('cas\\:proxies');
|
||||
for (let i = 0; i < elemProxies.length; i++) {
|
||||
proxies.push(cheerio(elemProxies[i]).text().trim());
|
||||
}
|
||||
|
||||
// Look for optional attributes
|
||||
const attributes = parseAttributes(elemSuccess, cheerio);
|
||||
|
||||
callback(undefined, true, username, {
|
||||
username,
|
||||
attributes,
|
||||
|
||||
PGTIOU: pgtIOU,
|
||||
ticket,
|
||||
proxies,
|
||||
});
|
||||
return;
|
||||
} // end if auth success
|
||||
|
||||
// Check for correctly formatted auth failure message
|
||||
const elemFailure = cheerio('cas\\:authenticationFailure').first();
|
||||
if (elemFailure && elemFailure.length > 0) {
|
||||
const code = elemFailure.attr('code');
|
||||
const message = `Validation failed [${code}]: ${elemFailure.text()}`;
|
||||
callback(new Error(message), false);
|
||||
return;
|
||||
}
|
||||
|
||||
// The response was not in any expected format, error
|
||||
callback(new Error('Bad response format.'));
|
||||
console.error(response);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Connection error with the CAS server
|
||||
req.on('error', function (err) {
|
||||
callback(err);
|
||||
req.abort();
|
||||
});
|
||||
}
|
||||
10
packages/cas-validate/tsconfig.json
Normal file
10
packages/cas-validate/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "@rocket.chat/tsconfig/server.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"declaration": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./src/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user