Merge pull request #904 from ansible/oauth_n_session

Implement session-based  and OAuth 2 authentications
This commit is contained in:
Christian Adams
2018-02-26 12:12:38 -05:00
committed by GitHub
50 changed files with 2127 additions and 624 deletions

View File

@@ -52,6 +52,7 @@ const watch = {
publicPath: '/static/',
host: '127.0.0.1',
port: 3000,
https: true,
proxy: {
'/': {
target: TARGET,

View File

@@ -374,7 +374,7 @@ angular
}
});
if (!Authorization.getToken() || !Authorization.isUserLoggedIn()) {
if (!Authorization.isUserLoggedIn()) {
// User not authenticated, redirect to login page
if (!/^\/(login|logout)/.test($location.path())) {
$rootScope.preAuthUrl = $location.path();

View File

@@ -21,21 +21,13 @@ export default
$injector) {
return {
setToken: function (token, expires) {
// set the session cookie
$cookies.remove('token');
$cookies.remove('token_expires');
$cookies.remove('userLoggedIn');
if (token && !(/^"[a-f0-9]+"$/ig.test(token))) {
$cookies.put('token', `"${token}"`);
} else {
$cookies.put('token', token);
}
$cookies.put('token_expires', expires);
$cookies.put('userLoggedIn', true);
$cookies.put('sessionExpired', false);
$rootScope.token = token;
$rootScope.userLoggedIn = true;
$rootScope.token_expires = expires;
$rootScope.sessionExpired = false;
@@ -44,43 +36,34 @@ export default
isUserLoggedIn: function () {
if ($rootScope.userLoggedIn === undefined) {
// Browser refresh may have occurred
$rootScope.userLoggedIn = $cookies.get('userLoggedIn');
$rootScope.sessionExpired = $cookies.get('sessionExpired');
$rootScope.userLoggedIn = ($cookies.get('userLoggedIn') === 'true');
$rootScope.sessionExpired = ($cookies.get('sessionExpired') === 'true');
}
return $rootScope.userLoggedIn;
},
getToken: function () {
if ($rootScope.token) {
return $rootScope.token;
}
let token = $cookies.get('token');
return token ? token.replace(/"/g, '') : undefined;
},
retrieveToken: function (username, password) {
return $http({
method: 'POST',
url: GetBasePath('authtoken'),
data: {
"username": username,
"password": password
},
headers: {
'Cache-Control': 'no-store',
'Pragma': 'no-cache'
}
var getCSRFToken = $http({
method: 'GET',
url: `/api/login/`
});
return getCSRFToken.then(function({data}) {
var csrfmiddlewaretoken = /name='csrfmiddlewaretoken' value='([0-9a-zA-Z]+)' \//.exec(data)[1];
// TODO: data needs to be encoded
return $http({
method: 'POST',
url: `/api/login/`,
data: `username=${username}&password=${password}&csrfmiddlewaretoken=${csrfmiddlewaretoken}&next=%2fapi%2f`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
});
},
deleteToken: function () {
return $http({
method: 'DELETE',
url: GetBasePath('authtoken'),
headers: {
'Authorization': 'Token ' + this.getToken()
}
method: 'GET',
url: '/api/logout/'
});
},
@@ -125,7 +108,6 @@ export default
SocketService.disconnect();
$cookies.remove('token_expires');
$cookies.remove('current_user');
$cookies.remove('token');
$cookies.put('userLoggedIn', false);
$cookies.put('sessionExpired', false);
$cookies.putObject('current_user', {});
@@ -134,7 +116,6 @@ export default
$rootScope.userLoggedIn = false;
$rootScope.sessionExpired = false;
$rootScope.licenseMissing = true;
$rootScope.token = null;
$rootScope.token_expires = null;
$rootScope.login_username = null;
$rootScope.login_password = null;
@@ -168,11 +149,7 @@ export default
getUser: function () {
return $http({
method: 'GET',
url: GetBasePath('me'),
headers: {
'Authorization': 'Token ' + this.getToken(),
"X-Auth-Token": 'Token ' + this.getToken()
}
url: GetBasePath('me')
});
},

View File

@@ -169,7 +169,7 @@ export default ['$log', '$cookies', '$compile', '$rootScope',
Authorization.retrieveToken(username, password)
.then(function (data) {
$('#login-modal').modal('hide');
Authorization.setToken(data.data.token, data.data.expires);
Authorization.setToken(data.data.expires);
scope.$emit('AuthorizationGetUser');
},
function (data) {

View File

@@ -55,8 +55,8 @@
*/
export default
['$http', '$rootScope', '$q', 'Authorization',
function ($http, $rootScope, $q, Authorization) {
['$http', '$rootScope', '$q',
function ($http, $rootScope, $q) {
return {
headers: {},
@@ -113,150 +113,88 @@ export default
args = (args) ? args : {};
this.params = (args.params) ? args.params : null;
this.pReplace();
var expired = this.checkExpired(),
token = Authorization.getToken();
var expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
return $http({
method: 'GET',
url: this.url,
headers: this.headers,
params: this.params
});
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
},
post: function (data) {
var token = Authorization.getToken(),
expired = this.checkExpired();
var expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
return $http({
method: 'POST',
url: this.url,
headers: this.headers,
data: data
});
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
},
put: function (data) {
var token = Authorization.getToken(),
expired = this.checkExpired();
var expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
return $http({
method: 'PUT',
url: this.url,
headers: this.headers,
data: data
});
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
},
patch: function (data) {
var token = Authorization.getToken(),
expired = this.checkExpired();
var expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
return $http({
method: 'PATCH',
url: this.url,
headers: this.headers,
data: data
});
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
},
destroy: function (data) {
var token = Authorization.getToken(),
expired = this.checkExpired();
var expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
return $http({
method: 'DELETE',
url: this.url,
headers: this.headers,
data: data
});
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
},
options: function (cache) {
var params,
token = Authorization.getToken(),
expired = this.checkExpired();
if (expired) {
return this.createResponse({
detail: 'Token is expired'
detail: 'Session is expired'
}, 401);
} else if (token) {
this.setHeader({
Authorization: 'Token ' + token
});
this.setHeader({
"X-Auth-Token": 'Token ' + token
});
} else {
params = {
method: 'OPTIONS',
url: this.url,
@@ -265,10 +203,6 @@ export default
cache: (cache ? true : false)
};
return $http(params);
} else {
return this.createResponse({
detail: 'Invalid token'
}, 401);
}
}
};

View File

@@ -165,7 +165,7 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
Alert('Conflict', data.conflict || "Resource currently in use.");
} else if (status === 410) {
Alert('Deleted Object', 'The requested object was previously deleted and can no longer be accessed.');
} else if ((status === 'Token is expired') || (status === 401 && data.detail && data.detail === 'Token is expired') ||
} else if ((status === 'Session is expired') || (status === 401 && data.detail && data.detail === 'Token is expired') ||
(status === 401 && data && data.detail && data.detail === 'Invalid token')) {
if ($rootScope.sessionTimer) {
$rootScope.sessionTimer.expireSession('idle');

View File

@@ -8,15 +8,17 @@ import {
AWX_E2E_PASSWORD
} from './settings';
let authenticated;
const session = axios.create({
baseURL: AWX_E2E_URL,
xsrfHeaderName: 'X-CSRFToken',
xsrfCookieName: 'csrftoken',
httpsAgent: new https.Agent({
rejectUnauthorized: false
})
}),
auth: {
username: AWX_E2E_USERNAME,
password: AWX_E2E_PASSWORD
}
});
const getEndpoint = location => {
@@ -27,36 +29,15 @@ const getEndpoint = location => {
return `${AWX_E2E_URL}/api/v2${location}`;
};
const authenticate = () => {
if (authenticated) {
return Promise.resolve();
}
const uri = getEndpoint('/authtoken/');
const credentials = {
username: AWX_E2E_USERNAME,
password: AWX_E2E_PASSWORD
};
return session.post(uri, credentials).then(res => {
session.defaults.headers.Authorization = `Token ${res.data.token}`;
authenticated = true;
return res;
});
};
const request = (method, location, data) => {
const uri = getEndpoint(location);
const action = session[method.toLowerCase()];
return authenticate()
.then(() => action(uri, data))
return action(uri, data)
.then(res => {
console.log([ // eslint-disable-line no-console
res.config.method.toUpperCase(),
uri,
res.config.url,
res.status,
res.statusText
].join(' '));