Socket
Socket
Sign inDemoInstall

cansecurity

Package Overview
Dependencies
73
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 2.1.0

example/example.js

13

lib/sessionManager.js

@@ -7,3 +7,3 @@ /*global module, require, Buffer, console */

now = util.now,
publicMethods, validate,
publicMethods, validate, invalidTokenMessage,
errors = require( './errors' ),

@@ -248,3 +248,3 @@ sender = require('./sender'),

var auth = getAuthTokenFromHeaders( req ), ret, token, login;
warn("Try Session with Auth Token for "+req.url);
warn("Try Session with Auth Token for "+req.url);
if ( auth ) {

@@ -255,3 +255,3 @@ warn("Auth Token found");

token = tokenlib.validate( auth );
// if succeeded, then we need to validate the user from the DB

@@ -261,3 +261,3 @@ if ( token ) {

warn("Successfully validated "+login+" via auth token");
if ( validate ) {

@@ -281,4 +281,4 @@ warn("Trying to check user ...");

warn("Failed to validate "+login+" via auth token");
endSessionWithErrorMessage( req, res, errors.invalidtoken() );
sender(res, 401, errors.invalidtoken() );
endSessionWithErrorMessage( req, res, errors.invalidtoken( invalidTokenMessage ) );
sender(res, 401, errors.invalidtoken( invalidTokenMessage ) );
}

@@ -330,2 +330,3 @@ ret = true;

validate = fnOrNull( config.validate );
invalidTokenMessage = config.invalidTokenMessage || null;
sessionExpiry = ( config.expiry || SESSIONEXPIRY ) * 60 * 1000;

@@ -332,0 +333,0 @@ encryptHeader = ( config.encryptHeader || false );

{
"name": "cansecurity",
"description": "cansecurity is your all-in-one security library for user authentication, authorization and management in node expressjs apps",
"version": "2.0.0",
"version": "2.1.0",
"url": "http://github.com/deitch/cansecurity",

@@ -6,0 +6,0 @@ "author": "Avi Deitcher <avi@deitcher.net>",

@@ -8,6 +8,4 @@ # cansecurity

**As of version 0.7.0, we support both restify and express.**
It's this simple:
It's this simple:
```Javascript

@@ -17,8 +15,8 @@ var express = require('express'), app = express(), cs = require('cansecurity'), cansec = cs.init(/* init params */);

app.user(app.router);
// send200 is a shortcut route to send a 200 response
// open route
app.get("/public",send200);
// only authorized if logged in, or as certain roles, or some combination

@@ -31,3 +29,3 @@ app.get("/secure/loggedin",cansec.restrictToLoggedIn,send200);

app.get("/secure/selfOrRoles/:user/adminOrSuper",cansec.restrictToSelfOrRoles(["admin","super"]),send200);
// only authorized if "searchParam" is set to the same value as the user ID field set in cs.init();

@@ -37,3 +35,3 @@ app.get("/secure/param",cansec.restrictToParam("searchParam"),send200);

app.get("/secure/paramOrMultipleRoles",cansec.restrictToParamOrRoles("searchParam",["admin","super"]),send200);
// only authorized if getCheckObject() returns an object, with field owner, that has a value matching the user ID field

@@ -46,3 +44,3 @@ app.get("/secure/field",cansec.restrictToField("owner",getCheckObject),send200);

app.get("/secure/fieldsOrRoles",cansec.restrictToFieldOrRoles(["owner","recipient"],["admin","super"],getCheckObject),send200);
// only authorized if the request parameter "private" has the value "true", and then restrict to logged in

@@ -57,3 +55,3 @@ app.get("/secure/conditionalDirect",cansec.ifParam("private","true").restrictToLoggedIn,send200);

// inside app.js:
// instantiate the user validator

@@ -63,3 +61,3 @@ app.use(cansec.validate);

app.use(cansec.authorizer(pathToAuthConfigFile));
// inside "pathToAuthConfigFile"

@@ -75,5 +73,5 @@ {

["PUT","/api/user/:user/roles","user.roles.admin === true"]
]
]
}
```

@@ -85,6 +83,10 @@

### Authentication
cansecurity will manage your user authentication, including managing stateless sessions. It can use either native express sessions and or its own **stateless** sessions. cansecurity stateless sessions can keep a user logged in automatically across multiple nodejs instances, essentially creating free single-sign-on.
cansecurity will manage your user authentication, including cross-server stateless sessions. It can use either native express sessions and or its own **stateless** sessions. cansecurity stateless sessions can keep a user logged in automatically across multiple nodejs instances, essentially creating free single-sign-on.
The flow looks like this:
![swimlanes](./swimlane.png)
### Authorization
cansecurity will handle authorization in your requests, determining if a user should be allowed to perform a certain request, based on your rules.
cansecurity will handle authorization in your requests, determining if a user should be allowed to perform a certain request, based on your rules.

@@ -112,3 +114,3 @@ You can tell cansecurity to manage your authorization imperatively (via middleware code) or declaratively (using a config file). Whatever works better for you is just fine for cansecurity!

The `initConfig` has six properties:
The `initConfig` has the following properties:

@@ -120,2 +122,3 @@ * `sessionExpiry`: OPTIONAL. Integer in minutes how long sessions should last, default is `15`. Used both for expressjs sessions and CS sessions. Setting `sessionExpiry` will **only** affect how long a session is valid **for cansecurity**. It will **not** affect the underlying expressjs session itself.

* `authHeader`: OPTIONAL. Replaces the header `X-CS-Auth` in which the server sends its token and user information back to the requestor/browser with the specified header name. `X-CS-Auth` is used *only* for sending the request from the server to the requestor (browser). The request to the server *always* is `Authentication`.
* `invalidTokenMessage`: OPTIONAL. Custom message to send back if an authentication is attempted with an invalid token.
* `debug`: OPTIONAL. Print debug messages about each authentication attempt to the console. It will **not** include the actual password.

@@ -149,3 +152,3 @@

You can also determine *how* the current user was authorized, credentials (e.g. password) and token, by calling
You can also determine *how* the current user was authorized, credentials (e.g. password) and token, by calling

@@ -180,3 +183,3 @@ ```JavaScript

`user`: the actual user object. This can be a function, a JavaScript object, anything you want. It will be placed inside the session and the request for you to use later. If retrieval/validation was successful, this must not be null/undefined.
`message` = the error message in case of retrieval/validation failure. This can be anything you want, and will be passed along with the 401 unauthenticated response.
`message` = the error message in case of retrieval/validation failure. This can be anything you want, and will be passed along with the 401 unauthenticated response.

@@ -198,7 +201,7 @@ If the user was already authenticated via session, token or some other method, then `validateUser()` will be called with `password` parameter set to `undefined`. If `password` is set to **anything** other than `undefined` (including a blank string), then `validateUser()` is expected to validate the password along with retrieving the user.

### Unauthenticated Errors
When authentication fails, cansecurity will directly return 401 with the message "unauthenticated".
When authentication fails, cansecurity will directly return 401 with the message "unauthenticated".
* If authentication is required and succeeds, it will set request["X-CS-Auth"], and request.session["X-CS-Auth"] if sessions are enabled, and then call next() to jump to the next middleware.
* If authentication is required and succeeds, it will set request["X-CS-Auth"], and request.session["X-CS-Auth"] if sessions are enabled, and then call next() to jump to the next middleware.
* If authentication is required and fails, it will return `401` with the text message `unauthenticated`
* If authentication is **not** required, it will jump to the next middleware
* If authentication is **not** required, it will jump to the next middleware

@@ -229,3 +232,3 @@ If the user has provided HTTP Basic Authentication credentials in the form of username/password **and** the authentication via `validate()` fails. In that case, cansecurity will return a `401`.

The `X-CS-Auth` response header contains error responses or success tokens.
The `X-CS-Auth` response header contains error responses or success tokens.

@@ -243,3 +246,3 @@ ##### Success

`token`: a JSON Web token if `success`, or an error message if `error`
`username`: the user's username if `success`
`username`: the username if `success`
`expiry`: when this token will expire, as a JavaScript (Unix) second timestamp, provided by `Math.floor(new Date().getTime()/1000)`

@@ -255,3 +258,3 @@

* `exp`: the expiry of the token. This is identical to the `expiry` field in the header response.
* `cs-user`: the actual logged in user when authentication by any means was successful.
* `cs-user`: the actual logged in user when authentication by any means was successful.

@@ -290,55 +293,4 @@

### Example
For a good example, see the test suite in test/test.js, specifically the section beginning cansec.init. It is reproduced below:
See the directory `./example/`
```JavaScript
var express = require('express'), app = express(), cs = require('cansecurity'), cansec,
// static database for testing
user = {name:"john",pass:"1234",age:25};
cansec = cs.init({
validate: function(login,password,callback){
if (user.name !== login) {
// no such user - ERROR
callback(false,null,"invaliduser");
} else if (password === undefined) {
// never asked to check a password, just send the user - GOOD
callback(true,user,user.name);
} else if (user.pass !== pass) {
// asked to check password, but it didn't match - ERROR
callback(false,null,"invalidpass");
} else {
// user matches, password matches - GOOD
callback(true,user,user.name);
}
},
sessionKey: SESSIONKEY
});
app.configure(function(){
app.use(express.cookieParser());
app.use(express.session({secret: "agf67dchkQ!"}));
app.use(cansec.validate);
app.use(function(req,res,next){
// send a 200
sendResponse(req,res,200);
});
});
app.user(function(err,req,res,next){
var data;
if (err && err.status) {
// one of ours
data = err.message ? {message: err.message} : null;
sendResponse(req,res,err.status,data);
} else if (err && err.type && err.type === "unexpected_token") {
// malformed data
sendResponse(req,res,{message:err.type},400);
} else {
sendResponse(req,res,500);
}
});
app.listen(PORT);
```
## Authorization

@@ -387,3 +339,3 @@ Authorization is the process of checking if a user is **allowed** to perform a certain action (in our case, execute a certain route), assuming they have already been authenticated (or not).

* params: OPTIONAL. Names of params passed as part of the expressjs route, and retrievable as this.params[param]. These params are used as part in some of the restrictTo* authorization middleware. There is currently one field:
* * params.id: Param in which the user ID is normally stored, if none is provided, then "user" is used. For example, if params.id === "foo", then the route should have /user/:foo.
* * params.id: Param in which the user ID is normally stored, if none is provided, then "user" is used. For example, if params.id === "foo", then the route should have /user/:foo.

@@ -397,3 +349,3 @@ Initialization returns the object that has the restrictTo* middleware.

// execute routeHandler() if user is logged in, else send 401
app.get("/some/route/:user",cansec.restrictToLoggedIn,routeHandler);
app.get("/some/route/:user",cansec.restrictToLoggedIn,routeHandler);
// execute routeHandler if req.param("user") === user[fields.id], where 'user' is as returned by validate(), else send 401

@@ -411,7 +363,7 @@ app.get("/my/data/:user",cansec.restrictToSelf,routeHandler);

#### Unauthorized Errors
cansecurity authorization will directly return a `403` and message `unauthorized` if authorization is required, i.e. a restrictTo* middleware is called, **and** fails.
cansecurity authorization will directly return a `403` and message `unauthorized` if authorization is required, i.e. a restrictTo* middleware is called, **and** fails.
Obviously, authentication comes before authorization, and if the user fails to authenticate, you may get a 401 from the authentication section without ever trying authorization.
#### Middleware API
#### Middleware API
The following authorization middleware methods are available. Each one is followed by an example. There are two sections

@@ -479,7 +431,7 @@

/*
* Will work if the logged in user has a property "userid" (since init() set fields.id to "userid"), and the value of that property matches req.param("searchParam").
* Will work if the logged in user has a property "userid" (since init() set fields.id to "userid"), and the value of that property matches req.param("searchParam").
* Useful for using parameters in searches.
*/
```
* restrictToParamOrRoles - user must have logged in and some field in the user object (fields.id) from authentication must equal some parameter in the URL or body (params.id) *or* user must have a specific role. Param argument and roles argument to the function may each be a string or an array of strings.

@@ -496,3 +448,3 @@

* Will work if one of the following is true:
* 1) the logged in user has a property "userid" (since init() set fields.id to "userid"), and the value of that property matches req.param("searchParam"), or, in the second example, one of "searchParam" or "addParam".
* 1) the logged in user has a property "userid" (since init() set fields.id to "userid"), and the value of that property matches req.param("searchParam"), or, in the second example, one of "searchParam" or "addParam".
* 2) The logged in user has the role, as one of the array of strings of the property "roles", set to "admin" or "superadmin" (for the first example), or "admin" (for the second example).

@@ -574,3 +526,3 @@ */

In the above example, anyone can do a GET on /api/employee, but if they pass the parameter ?secret=true, then they will have to be logged in and have the role "admin" defined.
In the above example, anyone can do a GET on /api/employee, but if they pass the parameter ?secret=true, then they will have to be logged in and have the role "admin" defined.

@@ -602,3 +554,3 @@ In our example, sendDataFn also checks for that parameter. If it is not set, then it sends public data about the employee list; if it is set, it sends public and private data, trusting that cansecurity prevented someone from getting in with ?secret=true unless they are authorized.

app.get("/public/page",send200);
// lots more
// lots more
app.get("*",function(req,res,next){res.send(403);});

@@ -654,3 +606,3 @@ ```

["PUT","/api/user/:user/roles","user.roles.admin === true"]
]
]
}

@@ -744,3 +696,3 @@ ```

1. `req`: the actual express `req` object, normally found on each route whose signature is `function(req,res,next)`.
1. `req`: the actual express `req` object, normally found on each route whose signature is `function(req,res,next)`.
2. `request`: an alias for `req`

@@ -752,3 +704,3 @@ 3. `user`: the user object if you used cansecurity authentication. This is the equivalent of calling `cansec.getUser(req)`.

#### Loading Data
You have the option, but not the requirement, to load data before passing your route through the declarative authorizer.
You have the option, but not the requirement, to load data before passing your route through the declarative authorizer.

@@ -826,3 +778,3 @@

fn1: function(req,res,next){},
fn2: function(req,res,next){}
fn2: function(req,res,next){}
}}))

@@ -928,3 +880,3 @@ ```

#### Changes to version 2.0.0
2.0.0 is a major release with many breaking changes.
2.0.0 is a major release with many breaking changes.

@@ -994,3 +946,3 @@ ##### JWT instead of multiple headers

#### Changes to version 0.5.0
These notes apply to anyone using cansecurity *prior* to v0.5.0. These changes may be breaking, so read carefully.
These notes apply to anyone using cansecurity *prior* to v0.5.0. These changes may be breaking, so read carefully.

@@ -1000,3 +952,3 @@ ##### express 3.x required

##### validatePassword and getUser consolidated into
##### validatePassword and getUser consolidated into
In versions of cansecurity prior to 0.5.0, there were two functions passed to `init()`:

@@ -1011,3 +963,3 @@

IF `validate()` is `undefined`, AND (`validatePassword()` and `getUser()`) are present, THEN cansecurity will use the old API.
IF `validate()` is `undefined`, AND (`validatePassword()` and `getUser()`) are present, THEN cansecurity will use the old API.

@@ -1017,2 +969,1 @@ IF `validate()` is defined, THEN (`validatePassword()` and `getUser()`) will be ignored, whether present or not.

Beginning with cansecurity 1.0, the old API will not function at all.
/*jslint node:true, nomen:true, unused:vars */
/*global before, it, describe, after */
var express = require('express'), restify = require('restify'), app, request = require('supertest'),
cansec, cs = require('./resources/cs'), errorHandler = require('./resources/error'),
cansec, cs = require('./resources/cs'), errorHandler = require('./resources/error'),
cookieParser = require('cookie-parser'),

@@ -168,3 +168,3 @@ session = require('express-session'),

app = express();
app.use(cookieParser());
app.use(cookieParser());
app.use(session({secret: "agf67dchkQ!",resave:false,saveUninitialized:false}));

@@ -175,6 +175,6 @@ app.use(cansec.validate);

app.use(errorHandler);
// we just send 200 for all routes, if it passes authorization
app.all('*',send200);
r = request(app);

@@ -188,3 +188,3 @@ });

app = express();
app.use(cookieParser());
app.use(cookieParser());
app.use(session({secret: "agf67dchkQ!",resave:false,saveUninitialized:false}));

@@ -195,6 +195,6 @@ app.use(cansec.validate);

app.use(errorHandler);
// we just send 200 for all routes, if it passes authorization
app.all('*',send200);
r = request(app);

@@ -208,3 +208,3 @@ });

app = express();
app.use(cookieParser());
app.use(cookieParser());
app.use(session({secret: "agf67dchkQ!",resave:false,saveUninitialized:false}));

@@ -216,6 +216,6 @@ app.use(cansec.validate);

app.use(errorHandler);
// we just send 200 for all routes, if it passes authorization
app.all('*',send200);
r = request(app);

@@ -244,3 +244,3 @@ });

app.head(/^.*$/,send200);
r = request(app);

@@ -261,3 +261,3 @@ });

app.use(cansec.authorizer(declareFile,{format:true}));
// we just send 200 for all routes, if it passes authorization

@@ -269,3 +269,3 @@ app.get(/^.*$/,send200);

app.head(/^.*$/,send200);
r = request(app);

@@ -272,0 +272,0 @@ });

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc