Skip to content

Commit

Permalink
Merge branch 'id_auth_to_support_x_ssl_client_cert_header'
Browse files Browse the repository at this point in the history
  • Loading branch information
tiblu committed Aug 29, 2018
2 parents e9cd8a5 + 3a7ec74 commit e10f089
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 21 deletions.
64 changes: 54 additions & 10 deletions routes/api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = function (app) {
var urlLib = app.get('urlLib');
var superagent = app.get('superagent');
var Promise = app.get('Promise');
var DigiDocServiceClient = app.get('ddsClient');

var User = app.get('models.User');
var UserConnection = app.get('models.UserConnection');
Expand Down Expand Up @@ -562,27 +563,70 @@ module.exports = function (app) {
/**
* Authenticate using ID-card
*
* NOTE: Requires proxy in front of the app to set "ssl_client_cert" header
* NOTE: Requires proxy in front of the app to set "X-SSL-Client-Cert" header
*/
app.post('/api/auth/id', function (req, res, next) {
var token = req.body.token; // Token to access the ID info service
var cert = req.headers['x-ssl-client-cert'];

if (!token) {
logger.warn('Missing required parameter "token"', req.path, req.headers);
if (!token && !cert) {
logger.warn('Missing required parameter "token" OR certificate in X-SSL-Client-Cert header. One must be provided!', req.path, req.headers);

return res.badRequest('Missing required parameter "token" OR certificate in X-SSL-Client-Cert header. One must be provided!');
}

var checkCertificatePromise = null;

if (cert) {
var ddsClient = new DigiDocServiceClient(config.services.digiDoc.serviceWsdlUrl, config.services.digiDoc.serviceName, config.services.digiDoc.token);
checkCertificatePromise = ddsClient
.checkCertificate(cert, false)
.spread(function (checkCertificateResult) {
var data = {
status: checkCertificateResult.Status.$value
};

return res.badRequest('Missing required parameter "token".');
switch (data.status) { // GOOD, UNKNOWN, EXPIRED, SUSPENDED
case 'GOOD':
data.user = {
pid: checkCertificateResult.UserIDCode.$value,
firstName: checkCertificateResult.UserGivenname.$value,
lastName: checkCertificateResult.UserSurname.$value,
countryCode: checkCertificateResult.UserCountry.$value // UPPERCASE ISO-2 letter
};
break;
case 'SUSPENDED':
case 'EXPIRED':
case 'UNKNOWN':
// Not giving User data for such cases - you're not supposed to use it anyway
logger.warn('Invalid certificate status', data.status);
break;
default:
logger.error('Unexpected certificate status from DDS', data.status);
res.internalServerError();

return Promise.reject();
}

return data;
});
} else {
checkCertificatePromise = superagent
.get(config.services.idCard.serviceUrl)
.query({token: token})
.set('X-API-KEY', config.services.idCard.apiKey)
.then(function (res) {
return res.body.data;
});
}

superagent
.get(config.services.idCard.serviceUrl)
.query({token: token})
.set('X-API-KEY', config.services.idCard.apiKey)
checkCertificatePromise
.then(function (res) {
var status = res.body.data.status;
var status = res.status;

switch (status) { //GOOD, UNKNOWN, EXPIRED, SUSPENDED, REVOKED
case 'GOOD':
return res.body.data.user;
return res.user;
case 'SUSPENDED':
res.badRequest('User certificate is suspended.', 24);

Expand Down
89 changes: 78 additions & 11 deletions test/api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ var _login = function (agent, email, password, expectedHttpCode, callback) {
var a = agent
.post(path)
.set('Content-Type', 'application/json')
.send({email: email, password: password})
.send({
email: email,
password: password
})
.expect(expectedHttpCode)
.expect('Content-Type', /json/);

Expand All @@ -34,6 +37,30 @@ var login = function (agent, email, password, callback) {
_login(agent, email, password, 200, callback);
};

var _loginId = function (agent, token, clientCert, expectedHttpCode, callback) {
var path = '/api/auth/id';

var a = agent
.post(path)
.set('Content-Type', 'application/json')
.expect(expectedHttpCode)
.expect('Content-Type', /json/);

if (clientCert) {
a.set('X-SSL-Client-Cert', clientCert);
}

if (token) {
a.send({token: token});
}

if (expectedHttpCode === 200) {
a.expect('set-cookie', /.*\.sid=.*; Path=\/api; Expires=.*; HttpOnly/);
}

a.end(callback);
};

/**
* Initialize Mobiil-ID login - call '/api/auth/mobile/init' API endpoint
*
Expand All @@ -52,7 +79,10 @@ var _loginMobileInit = function (agent, pid, phoneNumber, expectedHttpCode, call
agent
.post(path)
.set('Content-Type', 'application/json')
.send({pid: pid, phoneNumber: phoneNumber})
.send({
pid: pid,
phoneNumber: phoneNumber
})
.expect(expectedHttpCode)
.expect('Content-Type', /json/)
.end(callback);
Expand Down Expand Up @@ -183,7 +213,11 @@ var _signup = function (agent, email, password, language, expectedHttpCode, call
agent
.post(path)
.set('Content-Type', 'application/json')
.send({email: email, password: password, language: language})
.send({
email: email,
password: password,
language: language
})
.expect(expectedHttpCode)
.expect('Content-Type', /json/)
.end(callback);
Expand Down Expand Up @@ -223,7 +257,10 @@ var _passwordSet = function (agent, currentPassword, newPassword, expectedHttpCo
agent
.post(path)
.set('Content-Type', 'application/json')
.send({currentPassword: currentPassword, newPassword: newPassword})
.send({
currentPassword: currentPassword,
newPassword: newPassword
})
.expect(expectedHttpCode)
.expect('Content-Type', /json/)
.end(callback);
Expand Down Expand Up @@ -286,7 +323,11 @@ var _passwordResetComplete = function (agent, email, password, passwordResetCode
agent
.post(path)
.set('Content-Type', 'application/json')
.send({email: email, password: password, passwordResetCode: passwordResetCode})
.send({
email: email,
password: password,
passwordResetCode: passwordResetCode
})
.expect(expectedHttpCode)
.expect('Content-Type', /json/)
.end(callback);
Expand Down Expand Up @@ -384,6 +425,7 @@ module.exports._status = _status;
var request = require('supertest');
var app = require('../../app');
var uuid = require('node-uuid');
var fs = require('fs');

var assert = require('chai').assert;
var config = app.get('config');
Expand Down Expand Up @@ -451,7 +493,10 @@ suite('Auth', function () {
agent
.post('/api/auth/login')
.set('Content-Type', 'application/json')
.send({email: 'test_nonexistent_' + new Date().getTime() + '@test.ee', password: password})
.send({
email: 'test_nonexistent_' + new Date().getTime() + '@test.ee',
password: password
})
.expect(400)
.expect('Content-Type', /json/)
.end(function (err, res) {
Expand Down Expand Up @@ -496,7 +541,10 @@ suite('Auth', function () {
agent
.post('/api/auth/login')
.set('Content-Type', 'application/json')
.send({email: email, password: 'thisinvalidpassword'})
.send({
email: email,
password: 'thisinvalidpassword'
})
.expect(400)
.expect('Content-Type', /json/)
.end(function (err, res) {
Expand All @@ -514,8 +562,18 @@ suite('Auth', function () {
});
});

suite.skip('ID-card', function () {
// TODO: Create some
suite('ID-card', function () {

test('Success - client certificate in X-SSL-Client-Cert header', function (done) {
var agent = request.agent(app);
var cert = fs.readFileSync('./test/resources/certificates/dds_good_igor_sign.pem', {encoding: 'utf8'}).replace(/\n/g, ''); //eslint-disable-line no-sync

_loginId(agent, null, cert, 200, done);
});

test('Fail - no token or client certificate in header', function (done) {
_loginId(request.agent(app), null, null, 400, done);
});
});

suite('Mobiil-ID', function () {
Expand Down Expand Up @@ -1821,7 +1879,13 @@ suite('Auth', function () {
var agent = request.agent(app);

var path = '/api/auth/status';
var token = jwt.sign({id: 'notimportantinthistest', scope: 'all'}, config.session.privateKey, {expiresIn: '.1ms', algorithm: config.session.algorithm});
var token = jwt.sign({
id: 'notimportantinthistest',
scope: 'all'
}, config.session.privateKey, {
expiresIn: '.1ms',
algorithm: config.session.algorithm
});

agent
.get(path)
Expand Down Expand Up @@ -1924,7 +1988,10 @@ suite('Auth', function () {
return done(err);
}

var expectedUrl = urlLib.getFe('/:language/partners/:partnerId/consent', {partnerId: TEST_PARTNER.id, language: 'en'});
var expectedUrl = urlLib.getFe('/:language/partners/:partnerId/consent', {
partnerId: TEST_PARTNER.id,
language: 'en'
});

assert.equal(authRes.headers.location, expectedUrl);
// FIXME: Verify OpenID callback parameters!
Expand Down

0 comments on commit e10f089

Please sign in to comment.