Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/produck/cas-client

A complete implement of CAS Client middleware for Node.js, support CAS 1.0, 2.0+, 3.0+ protocol.
https://github.com/produck/cas-client

apereo cas-client cas-protocol cas-proxy koa nodejs

Last synced: 2 months ago
JSON representation

A complete implement of CAS Client middleware for Node.js, support CAS 1.0, 2.0+, 3.0+ protocol.

Awesome Lists containing this project

README

        

# http-cas-client
[![Build Status](https://img.shields.io/travis/lemonce/cas-client.svg?style=flat-square)](https://www.npmjs.com/package/http-cas-client)
[![NPM Downloads](https://img.shields.io/npm/dm/http-cas-client.svg?style=flat-square)](https://www.npmjs.com/package/http-cas-client)
[![NPM Version](https://img.shields.io/npm/v/http-cas-client.svg?style=flat-square)](https://www.npmjs.com/package/http-cas-client)

A complete implement of CAS Client middleware for Node.js, support CAS 1.0, 2.0+, 3.0+ protocol.

CAS(Central Authentication Service) is a single-sign-on / single-sign-off protocol for the web.

We suppose you are already familiar with the CAS protocol, if not, please read this [document](https://apereo.github.io/cas/6.0.x/protocol/CAS-Protocol.html) before you use this.

## Installation

```base
$ npm install http-cas-client
```

## Feature

* Singing Sign On (SSO)
* CAS Proxy with axios api for POST, PUT, DELETE...
* CAS Proxy - proxiex chain checking
* Single Logout (SLO)
* Renew & gateway
* Native http module supported
* No-session mode supported
* Easy to wrap for all popular backend framework integration
* Cluster friendly //TODO
* Principal adapter for application debugging //TODO
* SMAL1.1 //TODO
* Restlet integration supported //TODO
* Conditional skip CAS authentication //TODO
* PT cache //TODO

## Getting Started

### CAS Client Handler for Native

Basic usage with default options for creating a cas client handler and use it in nodejs native http server. For example,
```js
const http = require('http');
const httpCasClient = require('http-cas-client');

// A CAS server deployed at url http://localhost:8080.
// Default prefix is '/'.
const handler = httpCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1'
});

http.createServer(async (req, res) => {
if(!await handler(req, res)) {
return res.end();
}

const { principal, ticket } = req;
console.log(principal, ticket);
// { user: 'test', attributes: { ... } }

// your statements...
res.end('hello world');
}).listen(80);
```
### Koa2 Wrap
It can also use with popular backend framework like Koa2. For example,
```js
const koaCasClient = require('http-cas-client/wrap/koa2');
const Koa = require('koa');
const bodyparser = require('koa-bodyparser');

const casServerUrlPrefix = 'http://localhost:9000/cas';

const app = new Koa();

// NOTICE: If you put bodyparser after cas client, bodyparser will not receive req.socket data.
// A native body parser is used in handler.
// Sometimes you need to make some adjustments for your especial case.
app.use(bodyparser());

// NOTICE: Put the middleware include casClientHandler before your specific api code.
// For example, put it before routes.
app.use(koaCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1'
})).use(ctx => {
const { principal, ticket } = ctx;

// your statements...
ctx.body = `SLO

`

ctx.body += JSON.stringify(principal, null, 2);
ctx.body += '
'
}).listen(80);
```
Under the traditional pattern, cas client NEED to use with session, especially those 'Spring mvc' project in servlet.

So there is also a way to implement with all nodejs backend frameworks. For example in Koa2,
```js
const koaSessionCasClient = require('http-cas-client/wrap/koa2-session');
const session = require('koa-session');
const Koa = require('koa');
const casServerUrlPrefix = 'http://localhost:9000/cas';

const app = new Koa();
const sessionMiddleware = session(app);
app.keys = ['koa-app'];

app.use(session(app)).use(koaSessionCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1'
})).use(ctx => {
const { principal } = ctx;

// your statements...
ctx.body = `SLO

`

ctx.body += JSON.stringify(principal, null, 2);
ctx.body += '
'
}).listen(80);
```
### CAS Proxy (Use ServiceTicket instance)
```js
const koaSessionCasClient = require('http-cas-client/wrap/koa2-session');
const koaCasClient = require('http-cas-client/wrap/koa2');
const Koa = require('koa');
const session = require('koa-session');

const casServerUrlPrefix = 'http://localhost:9000/cas';

const app = new Koa();
app.keys = ['koa-app'];
app.use(session(app)).use(koaSessionCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1:2000',
client: {
proxy: {
callbackUrl: 'http://127.0.0.1:2000/callback',
receptorUrl: '/callback'
}
}
})).use((ctx, next) => {
// If req.url matches /app, skip into next middleware.
if (ctx.request.path === '/app') {
return next();
}

const { principal } = ctx;

// This is the 1st cas client.
// your statements...
ctx.body = `

This is proxy

`;
ctx.body = `SLO
`

ctx.body += JSON.stringify(principal, null, 2);
ctx.body += '
'
}).use(async ctx => {
const { ticket } = ctx;

// Proxy request some data from 2rd cas client 'http://127.0.0.1:3000'.
const response = await ticket.request('http://127.0.0.1:3000/').then(axios => {
return axios.post('/test');
});

// Proxy send the data from 2rd.
ctx.body = response.data;
}).listen(2000);

const app2 = new Koa();
app2.use(koaCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1:3000',
client: {
proxy: {
acceptAny: true,
callbackUrl: 'http://127.0.0.1:3000/proxyCallback',
receptorUrl: '/proxyCallback'
}
}
})).use(async ctx => {
//This is the 2nd cas client.
const { principal, ticket } = ctx;

// Proxy request some data from 3rd cas client 'http://127.0.0.1:4000/'.
const response = await ticket.request('http://127.0.0.1:4000/').then(axios => {
return axios.post('/test');
});

// your statements...
ctx.body = `

This is App

`;
ctx.body += `SLO
`;

ctx.body += JSON.stringify(principal, null, 2);
ctx.body += '
';

// Combine data from the 3rd.
ctx.body += response.data;
}).listen(3000);

const app3 = new Koa();
app3.use(koaCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1:4000',
client: {
proxy: {
acceptAny: true,
}
}
})).use(async ctx => {
// This is the 3rd cas client.
// your statements...
ctx.body = 'from the proxy proxy app.'
}).listen(4000);
```
### Custom Wrap
//TODO But you can review 'http-cas-client/wrap/koa2.js'. Maybe you can understand how to do.

At least I think that's easy. Good luck.

## API Referrence
### Options
The origin of CAS Server is essential. The simplest form is like,
```js
const httpCasClient = require('http-cas-client');
const handler = httpCasClient({
casServerUrlPrefix: 'http://localhost:9000/cas',
serverName: 'http://127.0.0.1',
});
```
#### Full Default Options
```js
// Other items are optional.
const defaultOptions = {
cas: 3, // CAS protocol version 1, 2, 3

client: {
service: null,
slo: true, // Use SLO?
renew: false, // CAS renew.
gateway: false, // CAS gateway
useSession: false,
method: 'GET',
// The resource path rules let cas client ignore.
ignore: [/\.(ico|css|js|jpe?g|svg|png)/],
proxy: {
acceptAny: false,
allowedChains: () => true,
callbackUrl: null,
receptorUrl: null
}
},

server: {
loginUrl: null,

// CAS Server URIs. Normally no change is required.
// Useful when use a nonstandard cas server or url re-writed.
path: {
login: '/login',
logout: '/logout',
validate: '/validate',
serviceValidate: '/serviceValidate',
proxyValidate: '/proxyValidate',
proxy: '/proxy',
p3: {
serviceValidate: '/p3/serviceValidate',
proxyValidate: '/p3/proxyValidate',
}
}
}
}
```
Why these paths? See also, [CAS Protocol 3.0 Specification](https://apereo.github.io/cas/5.2.x/protocol/CAS-Protocol-Specification.html#2-cas-uris).

#### Customs Options for Special Purposes
You can also override all items of options for your special cas server. And use chained multiple options arguments to create handler,
```js
const casClientHandler = httpCasClient(options1, options2, ...);
```
### Store
Store is an event emitter.
#### Method

//TODO

#### Event
//TODO

## CAS Client Cluster
### Shared Ticket Store
### Sync ST store
#### In Frontend
#### In Backend

## Debug
Because CAS protocol is complicated, we remove this option. We recommend you to always log every step that what CAS client do on your production environment.

Setting env.DEBUG="cas,cas:*";

## License

MIT