From 350d013043628c64e6baeaa7c9a477dc8a3d7c53 Mon Sep 17 00:00:00 2001 From: Robert Picard Date: Mon, 21 Dec 2015 18:34:07 -0500 Subject: [PATCH] Add Google SSO This pull request adds Google SSO support. There are two main changes: 1. Add the Google auth view resource 2. Make passwords optional when creating a new user. This allows an admin to create a user without a password so that they can only login via Google. --- lemur/auth/views.py | 41 +++++++++++++++++++ .../app/angular/users/user/user.tpl.html | 3 +- lemur/users/models.py | 12 ++++-- lemur/users/views.py | 2 +- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/lemur/auth/views.py b/lemur/auth/views.py index 8f93554e..6161e611 100644 --- a/lemur/auth/views.py +++ b/lemur/auth/views.py @@ -230,5 +230,46 @@ class Ping(Resource): return dict(token=create_token(user)) +class Google(Resource): + + def __init__(self): + self.reqparse = reqparse.RequestParser() + super(Google, self).__init__() + + def post(self): + access_token_url = 'https://accounts.google.com/o/oauth2/token' + people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect' + + self.reqparse.add_argument('clientId', type=str, required=True, location='json') + self.reqparse.add_argument('redirectUri', type=str, required=True, location='json') + self.reqparse.add_argument('code', type=str, required=True, location='json') + + args = self.reqparse.parse_args() + + # Step 1. Exchange authorization code for access token + payload = { + 'client_id': args['clientId'], + 'grant_type': 'authorization_code', + 'redirect_uri': args['redirectUri'], + 'code': args['code'], + 'client_secret': current_app.config.get('GOOGLE_SECRET') + } + + r = requests.post(access_token_url, data=payload) + token = r.json() + + # Step 2. Retrieve information about the current user + headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])} + + r = requests.get(people_api_url, headers=headers) + profile = r.json() + + user = user_service.get_by_email(profile['email']) + + if user: + return dict(token=create_token(user)) + + api.add_resource(Login, '/auth/login', endpoint='login') api.add_resource(Ping, '/auth/ping', endpoint='ping') +api.add_resource(Google, '/auth/google', endpoint='google') diff --git a/lemur/static/app/angular/users/user/user.tpl.html b/lemur/static/app/angular/users/user/user.tpl.html index c2e9687b..b19750b1 100644 --- a/lemur/static/app/angular/users/user/user.tpl.html +++ b/lemur/static/app/angular/users/user/user.tpl.html @@ -30,8 +30,7 @@ Password
- -

You must enter an password

+
diff --git a/lemur/users/models.py b/lemur/users/models.py index a3a13b1e..3a272d98 100644 --- a/lemur/users/models.py +++ b/lemur/users/models.py @@ -52,7 +52,10 @@ class User(db.Model): :param password: :return: """ - return bcrypt.check_password_hash(self.password, password) + if self.password: + return bcrypt.check_password_hash(self.password, password) + else: + return False def hash_password(self): """ @@ -60,8 +63,11 @@ class User(db.Model): :return: """ - self.password = bcrypt.generate_password_hash(self.password) - return self.password + if self.password: + self.password = bcrypt.generate_password_hash(self.password) + return self.password + else: + return None @property def is_admin(self): diff --git a/lemur/users/views.py b/lemur/users/views.py index 548caaeb..85093997 100644 --- a/lemur/users/views.py +++ b/lemur/users/views.py @@ -157,7 +157,7 @@ class UsersList(AuthenticatedResource): """ self.reqparse.add_argument('username', type=str, location='json', required=True) self.reqparse.add_argument('email', type=str, location='json', required=True) - self.reqparse.add_argument('password', type=str, location='json', required=True) + self.reqparse.add_argument('password', type=str, location='json', default=None) self.reqparse.add_argument('active', type=bool, default=True, location='json') self.reqparse.add_argument('roles', type=roles, default=[], location='json')