Merge pull request #187 from kevgliss/sso

Fixing some issues with dynamically supporting multiple SSO providers
This commit is contained in:
kevgliss 2015-12-27 22:06:31 -05:00
commit 665a3f3180
7 changed files with 161 additions and 152 deletions

View File

@ -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

View File

@ -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="">&laquo;</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="">&#8230;</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="">&raquo;</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="">&laquo;</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="">&#8230;</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="">&raquo;</a> </li> </ul> </div></div>');
}]);
}());

View File

@ -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;

View File

@ -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>

View File

@ -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(

View File

@ -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>

View File

@ -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):