Added basic Keystone authentication

authenticate() is called outside the constructor
so that the Keystone class plays nicely with
Promises. (It would be weird for the constructor
to return a Promise)

Change-Id: I3f9008d4d954c340178c77ec0433c5a1ddc971d2
This commit is contained in:
msmol 2016-07-27 15:55:34 -04:00 committed by Michael Krotscheck
parent 4e9cf48b43
commit e09ccbd473
2 changed files with 126 additions and 0 deletions

52
src/keystone.js Normal file
View File

@ -0,0 +1,52 @@
import 'isomorphic-fetch';
import log from 'loglevel';
log.setLevel('INFO');
export default class Keystone {
constructor(cloudsConfig, cloudName) {
if (cloudsConfig.clouds.hasOwnProperty(cloudName)) {
this.cloudConfig = cloudsConfig.clouds[cloudName];
} else {
throw new Error('Config for this cloud not found');
}
}
authenticate() {
const headers = {
'Content-Type': 'application/json'
};
const body = {
auth: {
identity: {
methods: ['password'],
password: {
user: {
name: this.cloudConfig.auth.username,
password: this.cloudConfig.auth.password
}
}
}
}
};
const init = {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
};
return fetch(this.cloudConfig.auth.auth_url, init)
.then((res) => {
this.token = res.headers.get('X-Subject-Token');
return res.json(); // This returns a promise...
})
.then((body) => {
this.catalog = body.catalog || {};
})
.catch((reason) => {
return reason;
});
}
}

74
test/unit/keystoneTest.js Normal file
View File

@ -0,0 +1,74 @@
import Keystone from '../../src/keystone.js';
import fetchMock from 'fetch-mock';
describe('Openstack connection test', () => {
it('should export a class', () => {
const keystone = new Keystone(aCloudsConfig('cloud1'), 'cloud1');
expect(keystone).toBeDefined();
});
it('should throw an error for an unknown cloud', () => {
const cloudsConfig = aCloudsConfig('cloud1');
const cloudName = 'cloud2';
try {
const keystone = new Keystone(cloudsConfig, cloudName);
keystone.authenticate();
} catch (e) {
expect(e.message).toEqual('Config for this cloud not found');
}
});
it('should authenticate', (done) => {
const cloudsConfig = aCloudsConfig('cloud1');
const authUrl = cloudsConfig.clouds.cloud1.auth.auth_url;
const cloudName = 'cloud1';
fetchMock
.post(authUrl, {
body: {
catalog: {
foo: 'bar'
}
},
headers: {
'X-Subject-Token': 'the-token'
}
});
const keystone = new Keystone(cloudsConfig, cloudName);
keystone.authenticate()
.then(() => {
expect(fetchMock.called(authUrl)).toEqual(true);
expect(typeof keystone.token).toEqual('string');
expect(keystone.token).toEqual('the-token');
expect(keystone.catalog).toEqual({foo: 'bar'});
done();
})
.catch((reason) => {
expect(reason).toBeUndefined();
done();
});
});
function aCloudsConfig (name) {
const cloudsConfig = {
clouds: {}
};
cloudsConfig.clouds[name] = {
region_name: 'Region1',
auth: {
username: 'user',
password: 'pass',
project_name: 'js-openstack-lib',
auth_url: 'http://keystone'
}
};
return cloudsConfig;
}
});