Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes required for signup flow #62

Merged
merged 8 commits into from Jan 18, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 7 additions & 10 deletions config/default.json
@@ -1,12 +1,9 @@
{
"host": "localhost",
"port": 3030,
"mongodb": "mongodb://localhost:27017/schulcloud",
"public": "../public/",
"auth": {
"token": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
},
"local": false
}
"host": "localhost",
"port": 3030,
"mongodb": "mongodb://localhost:27017/schulcloud",
"public": "../public/",
"auth": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
}
}
17 changes: 7 additions & 10 deletions config/production.json
@@ -1,12 +1,9 @@
{
"host": "localhost",
"port": 8080,
"mongodb": "mongodb://localhost:27017/schulcloud",
"public": "../public/",
"auth": {
"token": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
},
"local": false
}
"host": "localhost",
"port": 8080,
"mongodb": "mongodb://localhost:27017/schulcloud",
"public": "../public/",
"auth": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
}
}
17 changes: 7 additions & 10 deletions config/test.json
@@ -1,12 +1,9 @@
{
"host": "localhost",
"port": 3031,
"mongodb": "mongodb://localhost:27017/schulcloud-test",
"public": "../public/",
"auth": {
"token": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
},
"local": false
}
"host": "localhost",
"port": 3031,
"mongodb": "mongodb://localhost:27017/schulcloud-test",
"public": "../public/",
"auth": {
"secret": "FQ5lS1j41dcZdaPFPP3VRPH6W2bt8Z19bmvcVz+8SH8PtfVpVTl/p+9D0jIdRhwC1UrWg69lTU9koFgugf9oZg=="
}
}
36 changes: 19 additions & 17 deletions package.json
Expand Up @@ -18,8 +18,8 @@
"scripts": {
"lint": "eslint ./src ./test --ext .js",
"test": "./backup.sh -p setup/ -D schulcloud-test -a import && npm run lint && npm run coverage",
"backup": "./backup.sh -a -b export",
"setup": "./backup.sh -p setup/ -a import",
"backup": "./backup.sh -a -b export",
"setup": "./backup.sh -p setup/ -a import",
"start": "node src/",
"startd": "nodemon src/",
"coverage": "NODE_ENV=test istanbul cover node_modules/.bin/_mocha -- -- -u exports -R spec test/**/*.test.js",
Expand All @@ -34,29 +34,31 @@
"cors": "^2.8.1",
"es6-promisify": "^5.0.0",
"express": "^4.14.0",
"feathers": "^2.0.2",
"feathers-authentication": "^0.7.11",
"feathers-configuration": "^0.3.3",
"feathers-errors": "^2.4.0",
"feathers-hooks": "^1.5.8",
"feathers": "^2.0.3",
"feathers-authentication": "^1.0.2",
"feathers-authentication-jwt": "^0.3.1",
"feathers-authentication-local": "^0.3.2",
"feathers-configuration": "^0.4.1",
"feathers-errors": "^2.5.0",
"feathers-hooks": "^1.7.1",
"feathers-mongoose": "^3.6.1",
"feathers-rest": "^1.5.0",
"feathers-socketio": "^1.4.1",
"feathers-swagger": "^0.3.1",
"feathers-rest": "^1.6.0",
"feathers-socketio": "^1.4.2",
"feathers-swagger": "^0.3.2",
"freeport": "^1.0.5",
"istanbul": "^0.4.5",
"mongoose": "^4.6.4",
"mongoose": "^4.7.6",
"moodle-client": "^0.4.0",
"passport": "^0.3.2",
"phantomjs": "^2.1.7",
"request-promise-native": "^1.0.3",
"serve-favicon": "^2.3.0",
"winston": "^2.2.0"
"serve-favicon": "^2.3.2",
"winston": "^2.3.0"
},
"devDependencies": {
"eslint": "^3.8.1",
"eslint-plugin-react": "^6.4.1",
"mocha": "^3.1.2",
"request": "^2.75.0"
"eslint": "^3.13.1",
"eslint-plugin-react": "^6.9.0",
"mocha": "^3.2.0",
"request": "^2.79.0"
}
}
5 changes: 5 additions & 0 deletions src/app.js
Expand Up @@ -29,12 +29,17 @@ app.use(compress())
.use('/', serveStatic(app.get('public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({extended: true}))

.use(defaultHeaders)
.get('/system_info/haproxy', (req, res) => { res.send({ "timestamp":new Date().getTime() });})
.get('/ping', (req, res) => { res.send({ "message":"pong","timestamp":new Date().getTime() });})

.configure(hooks())
.configure(rest())
.configure(socketio())

// auth is setup in /authentication/

.configure(services)
.configure(middleware);

Expand Down
80 changes: 49 additions & 31 deletions src/services/account/hooks/index.js
@@ -1,41 +1,59 @@
'use strict';

const { ifNotLocal } = require('../../../hooks');
const auth = require('feathers-authentication');
const hooks = require('feathers-hooks');
const auth = require('feathers-authentication').hooks;
const local = require('feathers-authentication-local');
const errors = require('feathers-errors');

const MoodleLoginStrategy = require('../strategies/moodle');
const ITSLearningLoginStrategy = require('../strategies/itslearning');
const LernsaxLoginStrategy = require('../strategies/lernsax');
const LocalLoginStrategy = require('../strategies/local');

// don't initialize strategies here - otherwise massive overhead
const strategies = {
moodle: MoodleLoginStrategy,
itslearning: ITSLearningLoginStrategy,
lernsax: LernsaxLoginStrategy,
local: LocalLoginStrategy
};

exports.before = {
find: [
auth.verifyToken(),
auth.populateUser(),
auth.restrictToAuthenticated()
],
get: [
auth.verifyToken(),
auth.populateUser(),
auth.restrictToAuthenticated()
],
// find, get and create cannot be protected by auth.hooks.authenticate('jwt')
// otherwise we cannot get the accounts required for login
find: [],
get: [],
create: [
ifNotLocal(auth.hashPassword())
],
update: [
auth.verifyToken(),
auth.populateUser(),
auth.restrictToAuthenticated(),
auth.restrictToOwner({ownerField: '_id'})
],
patch: [
auth.verifyToken(),
auth.populateUser(),
auth.restrictToAuthenticated(),
auth.restrictToOwner({ownerField: '_id'})
(hook) => {
const {username, password, systemId, noVerification} = hook.data;

if(!username) throw new errors.BadRequest('no username specified');
if(!password) throw new errors.BadRequest('no password specified');

const app = hook.app;
const systemService = app.service('/systems');
return systemService.get(systemId)
.then(system => {
const strategy = strategies[system.type];
return {
strategy: new strategy(app),
system
};
})
.then(({strategy, system}) => {
return strategy.login({username, password}, system);
})
.then((client) => {
if (client.token) {
hook.data.token = client.token;
}
});
},
local.hooks.hashPassword({ passwordField: 'password' })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use inline hooks of more than 2 lines

],
remove: [
auth.verifyToken(),
auth.populateUser(),
auth.restrictToAuthenticated(),
auth.restrictToOwner({ownerField: '_id'})
]
update: [auth.hooks.authenticate('jwt')],
patch: [auth.hooks.authenticate('jwt')],
remove: [auth.hooks.authenticate('jwt')]
};

exports.after = {
Expand Down
23 changes: 2 additions & 21 deletions src/services/account/index.js
@@ -1,30 +1,11 @@
'use strict';

const Service = require('feathers-mongoose').Service;
const service = require('feathers-mongoose');
const account = require('./model');
const hooks = require('./hooks');

module.exports = function () {
const app = this;
const userService = app.service('/users');

class AccountService extends Service {
create(data, params, done) {
let account = null;
return super.create(data, params)
.then(newAccount => {
account = newAccount;
return userService.get(newAccount.userId);
})
.then(user => {
user.accounts.push(account._id);
return userService.update(user._id, user);
})
.then(user => {
return account;
});
}
}

const options = {
Model: account,
Expand All @@ -35,7 +16,7 @@ module.exports = function () {
};

// Initialize our service with any options it requires
app.use('/accounts', new AccountService(options));
app.use('/accounts', service(options));

// Get our initialize service to that we can bind hooks
const accountService = app.service('/accounts');
Expand Down
7 changes: 4 additions & 3 deletions src/services/account/model.js
Expand Up @@ -5,11 +5,12 @@ const Schema = mongoose.Schema;

const accountSchema = new Schema({
username: {type: String, required: true},
userId: {type: Schema.Types.ObjectId, required: true},
token: {type: String, required: false},
password: {type: String},

token: {type: String},
credentialHash: {type: String},

schoolId: {type: Schema.Types.ObjectId /*, required: true*/},
userId: {type: Schema.Types.ObjectId},
systemId: {type: Schema.Types.ObjectId, required: true},

expiresAt: {type: Date}
Expand Down
@@ -1,13 +1,12 @@
class AbstractLoginStrategy {
constructor() {
if (new.target === AbstractLoginStrategy) {
throw new TypeError("Cannot construct AbstractLoginStrategy instances directly");
throw new TypeError("Cannot construct AbstractLoginStrategy instances directly.");
}
}

// login is expected to take two parameters: credentials and system
if (typeof(this.login) != 'function') {
throw new TypeError("Must override login method");
}
login() {
throw new TypeError("login method has to be implemented.");
}
}

Expand Down
@@ -1,7 +1,3 @@
/**
* Created by niklas on 02/11/2016.
*/
'use strict';
const logger = require('winston');
const promisify = require('es6-promisify');
const errors = require('feathers-errors');
Expand Down
@@ -1,28 +1,16 @@
/**
* Created by carl on 21/10/2016.
*/
'use strict';


const moodleClient = require('moodle-client');
const logger = require('winston');
const promisify = require('es6-promisify');
const errors = require('feathers-errors');

const AbstractLoginStrategy = require('./interface');

//const userService = app.service('/users');


class MoodleLoginStrategy extends AbstractLoginStrategy {
constructor(app) {
super();
this.app = app;
}

/*
returns a promise with an authenticated client object, or the sign-in error
*/
login({username, password}, system) {

const moodleOptions = {
Expand Down
30 changes: 30 additions & 0 deletions src/services/authentication/hooks/index.js
@@ -0,0 +1,30 @@
'use strict';

const auth = require('feathers-authentication');
const local = require('feathers-authentication-local');
const jwt = require('feathers-authentication-jwt');

const logger = require('winston');

exports.before = {
create: [
auth.hooks.authenticate(['local', 'jwt']),
(hook) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before

const accountId = hook.params.payload.accountId;
return hook.app.service('/accounts').get(accountId).then((account) => {
if(account.userId) {
hook.params.payload.userId = account.userId;
}
return hook;
});
}
],
remove: [
auth.hooks.authenticate('jwt')
]
};

exports.after = {
create: [],
remove: []
};