Skip to content

Commit

Permalink
add basic authentication support (#304)
Browse files Browse the repository at this point in the history
  • Loading branch information
jupe authored Jul 19, 2019
1 parent d8dc2ad commit 678c35a
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 13 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ OpenTMI is Open Source Test Management System. It is written in [Node.js][Node.j
Javascript and uses [MongoDB][MongoDB] as backing store. It is published in [MIT license](LICENSE.md).
OpenTMI is extremely customizable through [addons](doc/addons.md).

![screenshot](doc/screenshot.jpg)
![logo](doc/images/OpenTMI_logo.png)

# Ideology

Basic idea is to store **all** information related to test execution to database, like software under test (SUT/Build), test logs, test cases (TC), and test related resources, like DUT's. That allows then much more intelligent and more efficient way to manage testing. Also it gives very valuable information when users can directly see what is tested in individual Device with individual Build. All information is linked together and can be analyzed very deeply.

## Challenges with SW testing in IoT HW
## Challenges with software testing in IoT hardware
* how to identify when test failed because of unstable HW
* how to identify unique unstable HW in test lab
* how to identify if certain test causes that HW's become unstable/unusable
* how to estimate when HW start to be unstable/unusable (e.g. memory start burning out)
* how to direct testing to right HW when there is multiple HW configurations
* how to identify if tools deployment (e.g. new test framework revision) causes more test failures
* how to execute right tests for different purpose if cannot run all of them for every commit (eg because of too long execution time)
* how to optimize test execution time
* how to manage all of these automatically

OpenTMI try to solve these kind of challenges using "big-data".
Expand Down
23 changes: 23 additions & 0 deletions app/controllers/passport/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const mongoose = require('mongoose');
const invariant = require('invariant');
const passport = require('passport');
const passportJWT = require('passport-jwt');
const HttpStrategy = require('passport-http').BasicStrategy;
const LocalStrategy = require('passport-local').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const GitHubStrategy = require('passport-github2').Strategy;
Expand Down Expand Up @@ -51,6 +52,7 @@ class PassportStrategies {
static createStrategies() {
PassportStrategies.JWTStrategy();
PassportStrategies.LocalStrategy();
PassportStrategies.HttpStrategy();
// github access token
const github = nconf.get('github');
if (github && _.get(github, 'clientID') !== '<client-id>') {
Expand Down Expand Up @@ -119,6 +121,27 @@ class PassportStrategies {
);
passport.use(localStrategy);
}
static HttpStrategy() {
passport.use(new HttpStrategy((userid, password, done) => {
const req = {name: userid};
logger.silly(`basic auth, findOne(${JSON.stringify(req)})`);
User.findOne(req)
.select('_id name email groups apikeys +password')
.exec()
.then((user) => {
invariant(user, 'Invalid email and/or password');
return user;
})
.then(user => user.comparePassword(password).return(user))
.then((user) => {
done(null, user);
})
.catch((error) => {
_.set(error, 'statusCode', 401);
done(error);
});
}));
}

static _GithubStrategyHelper(oauth2, accessToken, profile, next) {
logger.debug(`Profile: ${JSON.stringify(profile)}`);
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ class UsersController extends DefaultController {
.then(() => this.Model.findOne({
resetPasswordToken: req.body.token,
resetPasswordExpires: {$gt: Date.now()}
}
))
}))
.then((theUser) => {
const user = theUser;
if (!user) {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/middlewares/authorization.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function createJWT(user) {
});
}

const requireAuth = passport.authenticate('jwt', {session: false});
const requireAuth = passport.authenticate(['jwt', 'basic'], {session: false});
const ensureAdmin = [requireAuth, requireAdmin];

module.exports = {
Expand Down
62 changes: 57 additions & 5 deletions doc/APIs/authentication.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,72 @@
## Authentication

### Login
OpenTMI provides multiple authentication strategies:
* github OAuth
* jwt
* Local username/password
* basic authentication

To get JWT authorization token you have to use some of above login methods:


### Login using username and password
```
POST /auth/login
body: {username: <username>, password: <password>}
response: {token: <token>}
```

### Login using github OAuth

```
POST /auth/github
GET /auth/github/id get github client id
```


### Basic authentication

Client can include username and password to http request like:
```
curl https://admin:admin@localhost:3000/api/v0/events
```

**NOTE:** Do not use this when plain HTTP is in use!

### Signup new user

This is not needed when user login using github authentication.

```
POST /auth/signup
```


### Get authenticated user information

```
GET /auth/me
{ groups: [],
apikeys: [],
_id: '<string>',
name: '<string>',
email: '<string>',
registered: '<iso-date>',
lastVisited: '<iso-date>'
}
```

### Update user information

TBD
```
PUT /auth/me
POST /auth/signup
```

### Log out

```
POST /auth/logout
POST /auth/google
POST /auth/github
GET /auth/github/id get github client id
```

8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"passport-github-token": "^2.2.0",
"passport-github2": "^0.1.11",
"passport-google-oauth20": "^2.0.0",
"passport-http": "^0.3.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"request": "^2.88.0",
Expand Down
50 changes: 49 additions & 1 deletion test/tests_api/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const logger = require('winston');

// Setup
logger.level = 'error';
const {api, createUser, deleteUser} = require('./tools/helpers');
const {api, protocol, host, port, createUser, deleteUser} = require('./tools/helpers');


describe('authentication', function () {
Expand Down Expand Up @@ -71,6 +71,54 @@ describe('authentication', function () {
expect(body.token).to.be.an('string');
});
});
describe('basic', function () {
it('success', function () {
return superagent.get(`${protocol}://${name}:${password}@${host}:${port}/auth/me`)
.end()
.then(res => res.body)
.then((body) => {
expect(body._id).to.be.an('string');
expect(body.__v).to.be.an('number');
expect(body.loggedIn).to.be.an('boolean');
expect(body.groups).to.be.an('array');
expect(body.apikeys).to.be.an('array');
expect(body.name).to.be.equal(name);
expect(body.email).to.be.equal(email);
expect(body.registered).to.be.an('string');
expect(body.lastVisited).to.be.an('string');
});
});
it('invalid password', function () {
const url = `${protocol}://${name}:invalid@${host}:${port}/auth/me`;
return superagent.get(url)
.end()
.reflect()
.then((promise) => {
const {response} = promise.reason();
expect(promise.isRejected()).to.be.true;
expect(response.status).to.be.equal(401);
});
});
it('invalid username', function () {
const url = `${protocol}://invalid:${password}@${host}:${port}/auth/me`;
return superagent.get(url)
.end()
.reflect()
.then((promise) => {
const {response} = promise.reason();
expect(promise.isRejected()).to.be.true;
expect(response.status).to.be.equal(401);
});
});
});
it('logout', function () {
return superagent.post(`${protocol}://${name}:${password}@${host}:${port}/auth/logout`)
.end()
.then(res => res.body)
.then((body) => {
expect(body).to.be.deep.equal({});
});
});
});
describe('github', function () {
it('get clientID', function () {
Expand Down
8 changes: 7 additions & 1 deletion test/tests_api/tools/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ function createUserToken({
}

const testUserId = '5825bb7afe7545132c88c761';
const api = 'http://localhost:3000';
const protocol = 'http';
const host = 'localhost';
const port = '3000';
const api = `${protocol}://${host}:${port}`;
const apiV0 = `${api}/api/v0`;

function getTestUserToken() {
Expand Down Expand Up @@ -63,6 +66,9 @@ module.exports = {
createUserToken,
createUser,
deleteUser,
protocol,
port,
host,
api,
apiV0
};

0 comments on commit 678c35a

Please sign in to comment.