Skip to content

Commit

Permalink
Merge pull request #10 from romitkarmakar/master
Browse files Browse the repository at this point in the history
[Breaking Changes] Migrated to Typscript
  • Loading branch information
nodece authored Apr 24, 2020
2 parents b760aa4 + a4cce0a commit e72d894
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 127 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
build
12 changes: 12 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
]
}
3 changes: 0 additions & 3 deletions .eslintrc.json

This file was deleted.

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ typings/

package-lock.json
yarn.lock

dist/

build/
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,34 @@ npm install casbin@2 casbin-express-authz@1 --save
```shell
npm install casbin@3 casbin-express-authz@2 --save
```
or you can simply use,
```shell
npm install express casbin casbin-express-authz --save
```

## Usage with Basic HTTP Authentication

By default casbin-authz supports HTTP Basic Authentication of the form ```Authentication: Basic {Base64Encoded(username:password)}```

## Simple Example
## Usage with Other HTTP Authentication

To use other HTTP Authentication like ```Bearer/Digest``` you can use a custom middleware to define the ```res.locals.username``` variable and casbin-authz will automatically pick up the value from the variable.
```js
const { newEnforcer } = require('casbin')
const express = require('express')
const authz = require('casbin-express-authz')

const app = express()
const enforcer = newEnforcer('examples/authz_model.conf', 'examples/authz_policy.csv')

// set userinfo
app.use((req, res, next) => {
const username = req.get('Authorization') || 'anonymous'
req.user = {username}
res.locals.username = getUsernameFromToken() // Your custom function for retrieving username
next()
})

// use authz middleware
app.use(authz(async() => {
// load the casbin model and policy from files, database is also supported.
const enforcer = await newEnforcer('authz_model.conf', 'authz_policy.csv')
return enforcer
}))
app.use(authz(enforcer))

// response
app.use((req, res, next) => {
Expand Down
60 changes: 0 additions & 60 deletions authz.js

This file was deleted.

8 changes: 8 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
roots: ['<rootDir>/test'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
}
29 changes: 17 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"name": "casbin-express-authz",
"version": "2.0.0",
"version": "3.0.0",
"description": "casbin-express-authz is an authorization middleware for Express",
"main": "authz.js",
"main": "./build/authz.js",
"types": "./build/authz.d.ts",
"scripts": {
"prepublish": "npm run lint && npm run test",
"lint": "eslint \"authz.js\"",
"fix": "eslint \"authz.js\" --fix",
"prepublish": "npm run lint && npm run test && npm run build",
"build": "tsc",
"lint": "eslint . --ext .ts",
"fix": "eslint . --ext .ts --fix",
"test": "jest"
},
"keywords": [
Expand Down Expand Up @@ -38,15 +40,18 @@
"casbin": "^3.0.3"
},
"devDependencies": {
"@types/express": "^4.17.6",
"@types/jest": "^25.2.1",
"@types/node": "^13.11.1",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"coveralls": "^3.0.2",
"eslint": "^5.4.0",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^3.1.0",
"eslint": "^6.8.0",
"express": "^4.16.3",
"jest": "^23.5.0",
"supertest": "^3.1.0"
"supertest": "^3.1.0",
"ts-jest": "^25.4.0",
"ts-node": "^8.8.2",
"typescript": "^3.8.3"
}
}
78 changes: 78 additions & 0 deletions src/authz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2018 The Casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Enforcer } from "casbin"
import { Request, Response } from "express"

// BasicAuthorizer class stores the casbin handler
class BasicAuthorizer {
req: Request;
res: Response;
enforcer: Enforcer;
constructor(req: Request, res: Response, enforcer: Enforcer) {
this.req = req
this.res = res
this.enforcer = enforcer
}

// getUserName gets the user name from the request.
// Currently, only HTTP basic authentication is supported
getUserName(): string {
if (this.res.locals.username != undefined) return this.res.locals.username;

try {
const header: string = this.req.get("Authorization");
if (!header) return "";
const arr: Array<string> = header.split(" ");
if (arr[0].trim() != "Basic") return "";
const value: string = Buffer.from(arr[1], 'base64').toString('ascii');
const tempArr: Array<string> = value.split(":");
return tempArr[0];
} catch (e) {
console.log(e);
return "";
}

}

// checkPermission checks the user/method/path combination from the request.
// Returns true (permission granted) or false (permission forbidden)
async checkPermission(): Promise<boolean> {
const { req, enforcer } = this
const { originalUrl: path, method } = req
const user = this.getUserName()
const isAllowed = await enforcer.enforce(user, path, method)
return isAllowed
}
}

// authz returns the authorizer, uses a Casbin enforcer as input
export default function authz(newEnforcer: Promise<Enforcer>) {
return async (req: Request, res: Response, next): Promise<void> => {
const enforcer: Enforcer = await newEnforcer;
if (!(enforcer instanceof Enforcer)) {
res.status(500).json({ 500: 'Invalid enforcer' })
return
}
const authzorizer = new BasicAuthorizer(req, res, enforcer)
const isAllowed = await authzorizer.checkPermission()
if (!isAllowed) {
res.status(403).json({ 403: 'Forbidden' })
return
}
next()
}
}


2 changes: 1 addition & 1 deletion test/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "../.eslintrc.json",
"extends": "../.eslintrc",
"env": {
"jest": true
},
Expand Down
Loading

0 comments on commit e72d894

Please sign in to comment.