Skip to content

Commit

Permalink
KEYCLOAK-4946: Refactor of Node.js testsuite to support multiple clients
Browse files Browse the repository at this point in the history
- Provide client templates and make the testsuite reusable
- Add an option to retrieve client installation
- Methods to support the addition of clients
- Instead of create multiple realms per client. Create a single realm
for multiple clients
  • Loading branch information
Bruno Oliveira committed May 20, 2017
1 parent 0f39bc5 commit 167fc17
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 147 deletions.
12 changes: 6 additions & 6 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ var session = require('express-session');

var app = express();

var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});

// Register '.mustache' extension with The Mustache Express
app.set('view engine', 'html');
app.set('views', require('path').join(__dirname, '/view'));
Expand Down Expand Up @@ -74,9 +80,3 @@ app.get('/login', keycloak.protect(), function (req, res) {
event: '1. Authentication\n2. Login'
});
});

var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"roi": "^0.14.1",
"semistandard": "^9.2.1",
"tape": "^4.6.3",
"keycloak-admin-client": "^0.6.0",
"keycloak-admin-client": "bucharest-gold/keycloak-admin-client",
"hogan-express": "^0.5.2",
"selenium-webdriver": "^2.52.0",
"phantomjs-prebuilt":"^2.1.14"
Expand Down
40 changes: 18 additions & 22 deletions test/fixtures/node-console/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,33 @@
* License for the specific language governing permissions and limitations under
* the License.
*/

var Keycloak = require('../../../index');
var hogan = require('hogan-express');
var express = require('express');
var session = require('express-session');
var parse = require('../../utils/helper').parse;

function NodeApp (realm, file) {
this.kcConfig = parse('test/fixtures/public-client-template.json', realm);
function NodeApp () {
this.app = express();
var server = this.app.listen(0);
this.close = function () {
server.close();
};
this.port = server.address().port;

console.log('Example app listening at http://localhost:%s', this.port);
}

NodeApp.prototype.start = function start () {
var app = express();
app.set('view engine', 'html');
app.set('views', require('path').join(__dirname, '/views'));
app.engine('html', hogan);
NodeApp.prototype.build = function build (kcConfig) {
this.app.set('view engine', 'html');
this.app.set('views', require('path').join(__dirname, '/views'));
this.app.engine('html', hogan);

// Create a session-store to be used by both the express-session
// middleware and the keycloak middleware.

var memoryStore = new session.MemoryStore();

app.use(session({
this.app.use(session({
secret: 'mySecret',
resave: false,
saveUninitialized: true,
Expand All @@ -49,10 +53,10 @@ NodeApp.prototype.start = function start () {
// installed from the Keycloak web console.
var keycloak = new Keycloak({
store: memoryStore
}, this.kcConfig);
}, kcConfig);

// A normal un-protected public URL.
app.get('/', function (req, res) {
this.app.get('/', function (req, res) {
var authenticated = 'Init Success (' + (req.session['keycloak-token'] ? 'Authenticated' : 'Not Authenticated') + ')';
output(res, authenticated);
});
Expand All @@ -66,22 +70,14 @@ NodeApp.prototype.start = function start () {
// root URL. Various permutations, such as /k_logout will ultimately
// be appended to the admin URL.

app.use(keycloak.middleware({
this.app.use(keycloak.middleware({
logout: '/logout',
admin: '/'
}));

app.get('/login', keycloak.protect(), function (req, res) {
this.app.get('/login', keycloak.protect(), function (req, res) {
output(res, JSON.stringify(JSON.parse(req.session['keycloak-token']), null, 4), 'Auth Success');
});

var server = app.listen(0, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});

return server;
};

function output (res, output, eventMessage) {
Expand Down
64 changes: 0 additions & 64 deletions test/fixtures/realm-template.json

This file was deleted.

6 changes: 6 additions & 0 deletions test/fixtures/templates/bearerOnly-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"clientId": "{{name}}",
"adminUrl": "http://localhost:{{port}}",
"enabled": true,
"bearerOnly": true
}
13 changes: 13 additions & 0 deletions test/fixtures/templates/confidential-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"clientId": "{{name}}",
"rootUrl": "http://localhost:{{port}}",
"enabled": true,
"redirectUris": [
"http://localhost:{{port}}/*"
],
"webOrigins": [
"http://localhost:{{port}}/*"
],
"publicClient": false,
"secret": "5b5120a0-5e41-4cdd-af8a-72c470db0b59"
}
12 changes: 12 additions & 0 deletions test/fixtures/templates/public-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"clientId": "{{name}}",
"rootUrl": "http://localhost:{{port}}",
"enabled": true,
"redirectUris": [
"http://localhost:{{port}}/*"
],
"webOrigins": [
"http://localhost:{{port}}"
],
"publicClient": true
}
26 changes: 0 additions & 26 deletions test/fixtures/testrealm.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,5 @@
"description": "Administrator privileges"
}
]
},
"scopeMappings": [
{
"client": "js-console",
"roles": ["user"]
}
],
"clients": [
{
"clientId": "js-console",
"enabled": true,
"publicClient": true,
"baseUrl": "{{host}}:{{port}}",
"redirectUris": [
"{{host}}:{{port}}/*"
],
"webOrigins": []
}
],
"clientScopeMappings": {
"account": [
{
"client": "js-console",
"roles": ["view-profile"]
}
]
}
}
62 changes: 39 additions & 23 deletions test/keycloak-connect-web-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,67 +19,85 @@
const test = require('tape');
const page = require('./utils/webdriver').ConsolePage;
const AdminHelper = require('./utils/admin').AdminHelper;
const Type = require('./utils/admin').Type;
const TestVector = require('./utils/helper').TestVector;
const NodeApp = require('./fixtures/node-console/index').NodeApp;
// TODO remove
const parse = require('./utils/helper').parse;
const getAdminHelper = (baseUrl, username, password) => new AdminHelper(baseUrl, username, password);
const delay = (ms) => (value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));

let app = new NodeApp().start();
let realmManager = getAdminHelper().createRealm(app.address().port);
let realmManager = getAdminHelper().createRealm();
let app = new NodeApp();
let client;

test('setup', t => {
client = realmManager.then((realm) => {
return getAdminHelper().createClient(Type.publicClient(app.port));
});
t.end();
})

test('Should be able to access public page', t => {
realmManager.then((realm) => {
client.then((installation) => {
app.build(installation);

t.plan(1);
page.index(app.address().port);
page.index(app.port);
page.output().getText().then(function(text) {
t.equal(text, 'Init Success (Not Authenticated)');
t.equal(text, 'Init Success (Not Authenticated)', 'User should not be authenticated');
t.end();
}).catch((err) => {
t.fail('Test failed');
});
});
})
});
test('Should login with admin credentials', t => {
realmManager.then((realm) => {
client.then((installation) => {
app.build(installation);

t.plan(3);
page.index(app.address().port);
page.index(app.port);
page.output().getText().then(function(text) {
t.equal(text, 'Init Success (Not Authenticated)');
t.equal(text, 'Init Success (Not Authenticated)', 'User should not be authenticated');
})

page.logInButton().click();
page.login('user', 'password');

page.events().getText().then(function(text) {
t.equal(text, 'Auth Success');
t.equal(text, 'Auth Success', 'User should be authenticated');
})
page.logOutButton().click();
page.output().getText().then(function(text) {
t.equal(text, 'Init Success (Not Authenticated)');
t.equal(text, 'Init Success (Not Authenticated)', 'User should not be authenticated');
t.end();
}).catch((err) => {
t.fail('Test failed');
});
});
})

let nodeApp = new NodeApp('test-realm2');
nodeApp.kcConfig['realm-public-key'] = TestVector.wrongRealmPublicKey;
let app2 = nodeApp.start();

test('Should be forbidden for invalid public key', t => {
var realmManager = getAdminHelper().createRealm(app2.address().port, 'test-realm2');
realmManager.then((realm) => {
let app = new NodeApp();
var client = getAdminHelper().createClient(Type.publicClient(app.port, 'app2'));

client.then((installation) => {
installation['realm-public-key'] = TestVector.wrongRealmPublicKey;
app.build(installation);

t.plan(2);
page.index(app2.address().port);
page.index(app.port);
page.output().getText().then(function(text) {
t.equal(text, 'Init Success (Not Authenticated)');
t.equal(text, 'Init Success (Not Authenticated)', 'User should not be authenticated');
})
page.logInButton().click();
page.login('user', 'password');
page.body().getText().then(function (text) {
t.equal(text, 'Access denied');
t.equal(text, 'Access denied', 'Message should be access denied');
t.end();
}).then(() => {
app.close();
}).catch((err) => {
t.fail('Test failed');
});
Expand All @@ -88,10 +106,8 @@ test('Should be forbidden for invalid public key', t => {

test('teardown', t => {
app.close();
app2.close();
page.quit();
getAdminHelper().destroy('test-realm');
getAdminHelper().destroy('test-realm2');
page.quit();
t.end();
})

Loading

0 comments on commit 167fc17

Please sign in to comment.