Merge pull request #187 from kevgliss/sso
Fixing some issues with dynamically supporting multiple SSO providers
This commit is contained in:
commit
665a3f3180
|
@ -231,7 +231,6 @@ class Ping(Resource):
|
||||||
|
|
||||||
|
|
||||||
class Google(Resource):
|
class Google(Resource):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reqparse = reqparse.RequestParser()
|
self.reqparse = reqparse.RequestParser()
|
||||||
super(Google, self).__init__()
|
super(Google, self).__init__()
|
||||||
|
@ -271,34 +270,32 @@ class Google(Resource):
|
||||||
|
|
||||||
|
|
||||||
class Providers(Resource):
|
class Providers(Resource):
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
|
active_providers = []
|
||||||
active_providers = dict()
|
|
||||||
|
|
||||||
for provider in current_app.config.get("ACTIVE_PROVIDERS"):
|
for provider in current_app.config.get("ACTIVE_PROVIDERS"):
|
||||||
provider = provider.lower()
|
provider = provider.lower()
|
||||||
|
|
||||||
if provider == "google":
|
if provider == "google":
|
||||||
|
active_providers.append({
|
||||||
active_providers["google"] = {
|
'name': 'google',
|
||||||
'clientId': current_app.config.get("GOOGLE_CLIENT_ID"),
|
'clientId': current_app.config.get("GOOGLE_CLIENT_ID"),
|
||||||
'url': api.url_for(Google)
|
'url': api.url_for(Google)
|
||||||
}
|
})
|
||||||
|
|
||||||
elif provider == "ping":
|
elif provider == "ping":
|
||||||
|
active_providers.append({
|
||||||
active_providers["oauth2"] = {
|
|
||||||
'name': current_app.config.get("PING_NAME"),
|
'name': current_app.config.get("PING_NAME"),
|
||||||
'url': api.url_for(Ping),
|
'url': current_app.config.get('PING_REDIRECT_URI'),
|
||||||
'redirectUri': '', # TODO
|
'redirectUri': current_app.config.get("PING_REDIRECT_URI"),
|
||||||
'clientId': current_app.config.get("PING_CLIENT_ID"),
|
'clientId': current_app.config.get("PING_CLIENT_ID"),
|
||||||
'responseType': 'code',
|
'responseType': 'code',
|
||||||
'scope': ['openid', 'email', 'profile', 'address'],
|
'scope': ['openid', 'email', 'profile', 'address'],
|
||||||
'scopeDelimeter': ' ',
|
'scopeDelimeter': ' ',
|
||||||
'authorizationEndpoint': '', # TODO
|
'authorizationEndpoint': current_app.config.get("PING_AUTH_ENDPOINT"),
|
||||||
'requiredUrlParams': ['scope']
|
'requiredUrlParams': ['scope'],
|
||||||
}
|
'type': '2.0'
|
||||||
|
})
|
||||||
|
|
||||||
return active_providers
|
return active_providers
|
||||||
|
|
||||||
|
|
|
@ -1,139 +1,158 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var lemur = angular
|
(function() {
|
||||||
.module('lemur', [
|
var lemur = angular
|
||||||
'ui.router',
|
.module('lemur', [
|
||||||
'ngTable',
|
'ui.router',
|
||||||
'ngAnimate',
|
'ngTable',
|
||||||
'chart.js',
|
'ngAnimate',
|
||||||
'restangular',
|
'chart.js',
|
||||||
'angular-loading-bar',
|
'restangular',
|
||||||
'ui.bootstrap',
|
'angular-loading-bar',
|
||||||
'angular-spinkit',
|
'ui.bootstrap',
|
||||||
'toaster',
|
'angular-spinkit',
|
||||||
'uiSwitch',
|
'toaster',
|
||||||
'mgo-angular-wizard',
|
'uiSwitch',
|
||||||
'satellizer',
|
'mgo-angular-wizard',
|
||||||
'ngLetterAvatar',
|
'satellizer',
|
||||||
'angular-clipboard',
|
'ngLetterAvatar',
|
||||||
'ngFileSaver'
|
'angular-clipboard',
|
||||||
])
|
'ngFileSaver'
|
||||||
.config(function ($stateProvider, $urlRouterProvider, $authProvider, AuthenticationService) {
|
]);
|
||||||
$urlRouterProvider.otherwise('/welcome');
|
|
||||||
|
|
||||||
|
|
||||||
|
function fetchData() {
|
||||||
|
var initInjector = angular.injector(['ng']);
|
||||||
|
var $http = initInjector.get('$http');
|
||||||
|
|
||||||
|
return $http.get('http://localhost:8000/api/1/auth/providers').then(function(response) {
|
||||||
|
lemur.constant('providers', response.data);
|
||||||
|
}, function(errorResponse) {
|
||||||
|
console.log('Could not fetch SSO providers' + errorResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bootstrapApplication() {
|
||||||
|
angular.element(document).ready(function() {
|
||||||
|
angular.bootstrap(document, ['lemur']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData().then(bootstrapApplication);
|
||||||
|
|
||||||
|
lemur.config(function ($stateProvider, $urlRouterProvider, $authProvider, providers) {
|
||||||
|
$urlRouterProvider.otherwise('/welcome');
|
||||||
$stateProvider
|
$stateProvider
|
||||||
.state('welcome', {
|
.state('welcome', {
|
||||||
url: '/welcome',
|
url: '/welcome',
|
||||||
templateUrl: 'angular/welcome/welcome.html'
|
templateUrl: 'angular/welcome/welcome.html'
|
||||||
});
|
});
|
||||||
|
|
||||||
AuthenticationService.get_providers().then(function (active_providers) {
|
_.each(providers, function(provider) {
|
||||||
var provider_names = [];
|
if ($authProvider.hasOwnProperty(provider.name)) {
|
||||||
for (var key in active_providers) {
|
$authProvider[provider.name] = provider;
|
||||||
if (active_providers.hasOwnProperty(key)) {
|
|
||||||
provider_names.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i=0; i < provider_names.length; i++) {
|
|
||||||
$authProvider[provider_names[i]](active_providers[provider_names[i]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
lemur.service('MomentService', function () {
|
|
||||||
this.diffMoment = function (start, end) {
|
|
||||||
if (end !== 'None') {
|
|
||||||
return moment(end, 'YYYY-MM-DD HH:mm Z').diff(moment(start, 'YYYY-MM-DD HH:mm Z'), 'minutes') + ' minutes';
|
|
||||||
}
|
|
||||||
return 'Unknown';
|
|
||||||
};
|
|
||||||
this.createMoment = function (date) {
|
|
||||||
if (date !== 'None') {
|
|
||||||
return moment(date, 'YYYY-MM-DD HH:mm Z').fromNow();
|
|
||||||
}
|
|
||||||
return 'Unknown';
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
lemur.controller('datePickerController', function ($scope, $timeout){
|
|
||||||
$scope.open = function() {
|
|
||||||
$timeout(function() {
|
|
||||||
$scope.opened = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
lemur.service('DefaultService', function (LemurRestangular) {
|
|
||||||
var DefaultService = this;
|
|
||||||
DefaultService.get = function () {
|
|
||||||
return LemurRestangular.all('defaults').customGET().then(function (defaults) {
|
|
||||||
return defaults;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
lemur.factory('LemurRestangular', function (Restangular, $location, $auth) {
|
|
||||||
return Restangular.withConfig(function (RestangularConfigurer) {
|
|
||||||
RestangularConfigurer.setBaseUrl('http://localhost:8000/api/1');
|
|
||||||
RestangularConfigurer.setDefaultHttpFields({withCredentials: true});
|
|
||||||
|
|
||||||
RestangularConfigurer.addResponseInterceptor(function (data, operation) {
|
|
||||||
var extractedData;
|
|
||||||
|
|
||||||
// .. to look for getList operations
|
|
||||||
if (operation === 'getList') {
|
|
||||||
// .. and handle the data and meta data
|
|
||||||
extractedData = data.items;
|
|
||||||
extractedData.total = data.total;
|
|
||||||
} else {
|
} else {
|
||||||
extractedData = data;
|
$authProvider.oauth2(provider);
|
||||||
}
|
|
||||||
|
|
||||||
return extractedData;
|
|
||||||
});
|
|
||||||
|
|
||||||
RestangularConfigurer.setErrorInterceptor(function(response) {
|
|
||||||
if (response.status === 400) {
|
|
||||||
if (response.data.message) {
|
|
||||||
var data = '';
|
|
||||||
_.each(response.data.message, function (value, key) {
|
|
||||||
data = data + ' ' + key + ' ' + value;
|
|
||||||
});
|
|
||||||
response.data.message = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
RestangularConfigurer.addFullRequestInterceptor(function (element, operation, route, url, headers, params) {
|
|
||||||
// We want to make sure the user is auth'd before any requests
|
|
||||||
if (!$auth.isAuthenticated()) {
|
|
||||||
$location.path('/login');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var regExp = /\[([^)]+)\]/;
|
|
||||||
|
|
||||||
var s = 'sorting';
|
|
||||||
var f = 'filter';
|
|
||||||
var newParams = {};
|
|
||||||
for (var item in params) {
|
|
||||||
if (item.indexOf(s) > -1) {
|
|
||||||
newParams.sortBy = regExp.exec(item)[1];
|
|
||||||
newParams.sortDir = params[item];
|
|
||||||
} else if (item.indexOf(f) > -1) {
|
|
||||||
var key = regExp.exec(item)[1];
|
|
||||||
newParams.filter = key + ';' + params[item];
|
|
||||||
} else {
|
|
||||||
newParams[item] = params[item];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { params: newParams };
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
lemur.run(['$templateCache', function ($templateCache) {
|
lemur.service('MomentService', function () {
|
||||||
$templateCache.put('ng-table/pager.html', '<div class="ng-cloak ng-table-pager"> <div ng-if="params.settings().counts.length" class="ng-table-counts btn-group pull-left"> <button ng-repeat="count in params.settings().counts" type="button" ng-class="{\'active\':params.count()==count}" ng-click="params.count(count)" class="btn btn-default"> <span ng-bind="count"></span> </button></div><div class="pull-right"><ul style="margin: 0; padding: 0;" class="pagination ng-table-pagination"> <li ng-class="{\'disabled\': !page.active}" ng-repeat="page in pages" ng-switch="page.type"> <a ng-switch-when="prev" ng-click="params.page(page.number)" href="">«</a> <a ng-switch-when="first" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="page" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="more" ng-click="params.page(page.number)" href="">…</a> <a ng-switch-when="last" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="next" ng-click="params.page(page.number)" href="">»</a> </li> </ul> </div></div>');
|
this.diffMoment = function (start, end) {
|
||||||
}]);
|
if (end !== 'None') {
|
||||||
|
return moment(end, 'YYYY-MM-DD HH:mm Z').diff(moment(start, 'YYYY-MM-DD HH:mm Z'), 'minutes') + ' minutes';
|
||||||
|
}
|
||||||
|
return 'Unknown';
|
||||||
|
};
|
||||||
|
this.createMoment = function (date) {
|
||||||
|
if (date !== 'None') {
|
||||||
|
return moment(date, 'YYYY-MM-DD HH:mm Z').fromNow();
|
||||||
|
}
|
||||||
|
return 'Unknown';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
lemur.controller('datePickerController', function ($scope, $timeout){
|
||||||
|
$scope.open = function() {
|
||||||
|
$timeout(function() {
|
||||||
|
$scope.opened = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
lemur.service('DefaultService', function (LemurRestangular) {
|
||||||
|
var DefaultService = this;
|
||||||
|
DefaultService.get = function () {
|
||||||
|
return LemurRestangular.all('defaults').customGET().then(function (defaults) {
|
||||||
|
return defaults;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
lemur.factory('LemurRestangular', function (Restangular, $location, $auth) {
|
||||||
|
return Restangular.withConfig(function (RestangularConfigurer) {
|
||||||
|
RestangularConfigurer.setBaseUrl('http://localhost:8000/api/1');
|
||||||
|
RestangularConfigurer.setDefaultHttpFields({withCredentials: true});
|
||||||
|
|
||||||
|
RestangularConfigurer.addResponseInterceptor(function (data, operation) {
|
||||||
|
var extractedData;
|
||||||
|
|
||||||
|
// .. to look for getList operations
|
||||||
|
if (operation === 'getList') {
|
||||||
|
// .. and handle the data and meta data
|
||||||
|
extractedData = data.items;
|
||||||
|
extractedData.total = data.total;
|
||||||
|
} else {
|
||||||
|
extractedData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractedData;
|
||||||
|
});
|
||||||
|
|
||||||
|
RestangularConfigurer.setErrorInterceptor(function(response) {
|
||||||
|
if (response.status === 400) {
|
||||||
|
if (response.data.message) {
|
||||||
|
var data = '';
|
||||||
|
_.each(response.data.message, function (value, key) {
|
||||||
|
data = data + ' ' + key + ' ' + value;
|
||||||
|
});
|
||||||
|
response.data.message = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RestangularConfigurer.addFullRequestInterceptor(function (element, operation, route, url, headers, params) {
|
||||||
|
// We want to make sure the user is auth'd before any requests
|
||||||
|
if (!$auth.isAuthenticated()) {
|
||||||
|
$location.path('/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var regExp = /\[([^)]+)\]/;
|
||||||
|
|
||||||
|
var s = 'sorting';
|
||||||
|
var f = 'filter';
|
||||||
|
var newParams = {};
|
||||||
|
for (var item in params) {
|
||||||
|
if (item.indexOf(s) > -1) {
|
||||||
|
newParams.sortBy = regExp.exec(item)[1];
|
||||||
|
newParams.sortDir = params[item];
|
||||||
|
} else if (item.indexOf(f) > -1) {
|
||||||
|
var key = regExp.exec(item)[1];
|
||||||
|
newParams.filter = key + ';' + params[item];
|
||||||
|
} else {
|
||||||
|
newParams[item] = params[item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { params: newParams };
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lemur.run(['$templateCache', function ($templateCache) {
|
||||||
|
$templateCache.put('ng-table/pager.html', '<div class="ng-cloak ng-table-pager"> <div ng-if="params.settings().counts.length" class="ng-table-counts btn-group pull-left"> <button ng-repeat="count in params.settings().counts" type="button" ng-class="{\'active\':params.count()==count}" ng-click="params.count(count)" class="btn btn-default"> <span ng-bind="count"></span> </button></div><div class="pull-right"><ul style="margin: 0; padding: 0;" class="pagination ng-table-pagination"> <li ng-class="{\'disabled\': !page.active}" ng-repeat="page in pages" ng-switch="page.type"> <a ng-switch-when="prev" ng-click="params.page(page.number)" href="">«</a> <a ng-switch-when="first" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="page" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="more" ng-click="params.page(page.number)" href="">…</a> <a ng-switch-when="last" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="next" ng-click="params.page(page.number)" href="">»</a> </li> </ul> </div></div>');
|
||||||
|
}]);
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,12 @@ angular.module('lemur')
|
||||||
controller: 'LoginController'
|
controller: 'LoginController'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.controller('LoginController', function ($rootScope, $scope, AuthenticationService, UserService) {
|
.controller('LoginController', function ($rootScope, $scope, AuthenticationService, UserService, providers) {
|
||||||
$scope.login = AuthenticationService.login;
|
$scope.login = AuthenticationService.login;
|
||||||
$scope.authenticate = AuthenticationService.authenticate;
|
$scope.authenticate = AuthenticationService.authenticate;
|
||||||
$scope.logout = AuthenticationService.logout;
|
$scope.logout = AuthenticationService.logout;
|
||||||
$scope.get_providers = AuthenticationService.get_providers;
|
|
||||||
|
$scope.providers = providers;
|
||||||
|
|
||||||
UserService.getCurrentUser().then(function (user) {
|
UserService.getCurrentUser().then(function (user) {
|
||||||
$scope.currentUser = user;
|
$scope.currentUser = user;
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 col-sm-12 col-md-12">
|
<div class="col-xs-12 col-sm-12 col-md-12">
|
||||||
<button class="btn btn-block btn-default" ng-repeat="(key, value) in get_providers()" ng-click="authenticate(key)">
|
<button class="btn btn-block btn-default" ng-repeat="(key, value) in providers" ng-click="authenticate(value.name)">
|
||||||
Login with {{key}}
|
Login with {{ value.name }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,10 +6,6 @@ angular.module('lemur')
|
||||||
.service('AuthenticationService', function ($location, $rootScope, AuthenticationApi, UserService, toaster, $auth) {
|
.service('AuthenticationService', function ($location, $rootScope, AuthenticationApi, UserService, toaster, $auth) {
|
||||||
var AuthenticationService = this;
|
var AuthenticationService = this;
|
||||||
|
|
||||||
AuthenticationService.get_providers = function () {
|
|
||||||
return AuthenticationApi.one('providers').get();
|
|
||||||
};
|
|
||||||
|
|
||||||
AuthenticationService.login = function (username, password) {
|
AuthenticationService.login = function (username, password) {
|
||||||
AuthenticationApi.customPOST({'username': username, 'password': password}, 'login')
|
AuthenticationApi.customPOST({'username': username, 'password': password}, 'login')
|
||||||
.then(
|
.then(
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<!-- endbuild -->
|
<!-- endbuild -->
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body ng-app="lemur" ng-csp>
|
<body ng-csp>
|
||||||
<toaster-container></toaster-container>
|
<toaster-container></toaster-container>
|
||||||
<!--[if lt IE 7]>
|
<!--[if lt IE 7]>
|
||||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
|
|
|
@ -54,8 +54,6 @@ class User(db.Model):
|
||||||
"""
|
"""
|
||||||
if self.password:
|
if self.password:
|
||||||
return bcrypt.check_password_hash(self.password, password)
|
return bcrypt.check_password_hash(self.password, password)
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def hash_password(self):
|
def hash_password(self):
|
||||||
"""
|
"""
|
||||||
|
@ -66,8 +64,6 @@ class User(db.Model):
|
||||||
if self.password:
|
if self.password:
|
||||||
self.password = bcrypt.generate_password_hash(self.password)
|
self.password = bcrypt.generate_password_hash(self.password)
|
||||||
return self.password
|
return self.password
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_admin(self):
|
def is_admin(self):
|
||||||
|
|
Loading…
Reference in New Issue