Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Goodbye Google #565

Merged
merged 4 commits into from
May 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion backend/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ def get(self):
'email': user.email,
'affiliation': user.affiliation,
'country': user.country,
'login_type': self.get_secure_cookie('identity_type').decode('utf-8'),
}

self.finish(ret)
Expand Down
179 changes: 0 additions & 179 deletions backend/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def get(self):
self.set_secure_cookie('user', self.get_argument("user"))
self.set_secure_cookie('email', self.get_argument("email"))
self.set_secure_cookie('identity', self.get_argument("email"))
self.set_secure_cookie('identity_type', 'google')
self.finish()


Expand Down Expand Up @@ -56,27 +55,10 @@ async def get(self):
user_token = await self.get_user_token(self.get_argument('code'))
user = await self.get_user(user_token["access_token"])

extra_login = None
try: # check if the user is already logged in
extra_login = self.get_secure_cookie('identity_type').decode('utf-8')

# Store other login in separate cookies (elixir is main login)
# This is hardcoded for google right now, as that is the only option
if extra_login == 'google':
google_identity = self.get_secure_cookie('identity').decode('utf-8')
self.set_secure_cookie('google_identity', google_identity)

except AttributeError: # if the user isn't logged in
pass

self.set_secure_cookie('access_token', user_token["access_token"])
self.set_secure_cookie('user', user["name"])
self.set_secure_cookie('email', user["email"])
self.set_secure_cookie('identity', user["sub"])
self.set_secure_cookie('identity_type', 'elixir')

if extra_login:
self.set_secure_cookie('identity_type', 'elixir_%s' % extra_login)

redirect = self.get_secure_cookie("login_redirect")
self.clear_cookie("login_redirect")
Expand Down Expand Up @@ -162,164 +144,3 @@ def get(self):
self.redirect(redirect)


class GoogleLoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
"""
See http://www.tornadoweb.org/en/stable/auth.html#google for documentation
on this. Here I have copied the example more or less verbatim.
"""
@tornado.gen.coroutine
def get(self):
if self.get_argument("code", False):
logging.debug("Requesting user token")
user_token = yield self.get_authenticated_user(
redirect_uri=self.application.settings['redirect_uri'],
code=self.get_argument('code'),
callback = lambda *_, **__: None)

logging.debug("Requesting user info")
user = yield self.oauth2_request(
"https://www.googleapis.com/plus/v1/people/me",
access_token=user_token["access_token"],
callback = lambda *_, **__: None)

try:
# Check if there is the user is already in the database.
# This will generate an exception if the user does not exist, preventing login
db.User.select().where(db.User.identity == self._get_google_email(user)).get()

extra_login = None
try: # check if the user is already logged in
extra_login = self.get_secure_cookie('identity_type').decode('utf-8')

# Store this login in separate cookies (elixir is main login)
# This is hardcoded for elixir right now, as that is the only option
if extra_login == 'elixir':
google_identity = self._get_google_email(user)
self.set_secure_cookie('google_identity', google_identity)

self.set_secure_cookie('identity_type', '%s_google' % extra_login)

except AttributeError: # if the user isn't logged in
self.set_secure_cookie('user', user["displayName"])
self.set_secure_cookie('access_token', user_token["access_token"])
self.set_secure_cookie('email', self._get_google_email(user))
self.set_secure_cookie('identity', self._get_google_email(user))
self.set_secure_cookie('identity_type', 'google')

except db.User.DoesNotExist:
msg = "You have no user information logged in our database, so you may directly log in using elixir without updating."
self.set_user_msg(msg, "success")

url = self.get_secure_cookie("login_redirect")
self.clear_cookie("login_redirect")
if url is None:
url = '/'
self.redirect(url)

else:
logging.debug("Redirecting to google for login")
self.set_secure_cookie('login_redirect', self.get_argument("next", '/'), 1)
self.authorize_redirect(
redirect_uri=self.application.settings['redirect_uri'],
client_id=self.application.oauth_key,
scope=['profile', 'email'],
response_type='code',
extra_params={'approval_prompt': 'auto'})

def _get_google_email(self, user): #pylint: disable=no-self-use
email = ''
# There can be several emails registered for a user.
for email in user["emails"]:
if email.get('type', '') == 'account':
return email['value']

return user['emails'][0]['value']


class GoogleLogoutHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
def get(self):
def handle_request(response):
if response.error:
logging.info("Error, failed in logout")
logging.info(response.error)
else:
logging.info("User logged out")

sAccessToken = self.get_secure_cookie("access_token")
sLogoutUrl = "https://accounts.google.com/o/oauth2/revoke?token=" + str(sAccessToken)
http_client = tornado.httpclient.AsyncHTTPClient()
http_client.fetch(sLogoutUrl, handle_request)

self.clear_all_cookies()

redirect = self.get_argument("next", '/')
self.redirect(redirect)


class UpdateUserHandler(handlers.SafeHandler):
def post(self):
"""
If a user is logged in to elixir, and also has google login cookies, the
google users information in the database will be updated with the elixir
users information.
"""
# set redirect
try:
redirect = self.get_argument("next")
except tornado.web.MissingArgumentError:
redirect = self.get_cookie("login_redirect", '/')
self.clear_cookie("login_redirect")

try:
# Double check so that the elixir user isn't already have any credentials
# in the database.

elixir_identity = self.get_secure_cookie('user')

(db.User.select()
.join(db.DatasetAccess)
.where(
db.User.user == db.DatasetAccess.user,
db.User.identity == elixir_identity)
.get())
msg = "This elixir account already has its own credentials. Sadly, you will have to contact us directly to merge your accounts."
self.set_user_msg(msg, "error")
self.finish({'redirect':'/login'})
return
except db.User.DoesNotExist:
# This is what we want
pass

try:
# Check if we have a google login, will throw an AttributeError
# if the cookie isn't available
google_identity = self.get_secure_cookie('google_identity').decode('utf-8')

# Try to update the google user in the database with the elixir information
# This throws a peewee.IntegrityError if the elixir account is already in
# the database
db.User.update( name = self.get_secure_cookie('user').decode('utf-8'),
email = self.get_secure_cookie('email').decode('utf-8'),
identity = self.get_secure_cookie('identity').decode('utf-8'),
identity_type = 'elixir'
).where( db.User.identity == google_identity ).execute()

self.set_secure_cookie('identity_type', 'updated')
except AttributeError:
# This will happen when we don't have a google cookie
msg = "You need to log in to a google account to be able to transfer credentials"
self.set_user_msg(msg, "info")

self.finish({'redirect':'/login'})
return
except peewee.IntegrityError:
# This will happen if the elixir account is already in the database
msg = "This elixir account is already in our database, so it can't be used to update another google account."
self.set_user_msg(msg, "error")
self.finish({'redirect':'/login'})
return

msg = "Your account has been updated! You may now use the site as you used to, using your Elixir account."
self.set_user_msg(msg, "success")

self.finish({'redirect':redirect})
2 changes: 1 addition & 1 deletion backend/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ class Meta:
name = CharField(db_column="username", null=True)
email = CharField(unique=True)
identity = CharField(unique=True)
identity_type = EnumField(null=False, choices=['google', 'elixir'])
identity_type = EnumField(null=False, choices=['google', 'elixir'], default='elixir')
affiliation = CharField(null=True)
country = CharField(null=True)

Expand Down
4 changes: 1 addition & 3 deletions backend/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def get_current_user(self):
email = self.get_secure_cookie('email')
name = self.get_secure_cookie('user')
identity = self.get_secure_cookie('identity')
identity_type = self.get_secure_cookie('identity_type')

# Fix ridiculous bug with quotation marks showing on the web
if name and (name[0] == '"') and (name[-1] == '"'):
Expand All @@ -49,8 +48,7 @@ def get_current_user(self):
try:
return db.User(email = email.decode('utf-8'),
name = name.decode('utf-8'),
identity = identity.decode('utf-8'),
identity_type = identity_type.decode('utf-8'))
identity = identity.decode('utf-8'))
except peewee.OperationalError as e:
logging.error("Can't create new user: {}".format(e))
else:
Expand Down
11 changes: 0 additions & 11 deletions backend/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,11 @@
tornado_settings = {"debug": False,
"cookie_secret": swefreq_settings.cookie_secret,
"login_url": "/login",
"google_oauth": {
"key": swefreq_settings.google_key,
"secret": swefreq_settings.google_secret
},
"elixir_oauth": {
"id": swefreq_settings.elixir["id"],
"secret": swefreq_settings.elixir["secret"],
"redirect_uri": swefreq_settings.elixir["redirectUri"],
},
"redirect_uri": swefreq_settings.redirect_uri,
"xsrf_cookies": True,
"template_path": "templates/",
}
Expand All @@ -49,10 +44,7 @@ def __init__(self, settings):
(r"/logout", auth.ElixirLogoutHandler),
(r"/elixir/login", auth.ElixirLoginHandler),
(r"/elixir/logout", auth.ElixirLogoutHandler),
(r"/google/login", auth.GoogleLoginHandler),
(r"/google/logout", auth.GoogleLogoutHandler),
## API Methods
(r"/api/users/elixir_transfer", auth.UpdateUserHandler),
(r"/api/countries", application.CountryList),
(r"/api/users/me", application.GetUser),
(r"/api/users/datasets", application.UserDatasetAccess),
Expand Down Expand Up @@ -93,9 +85,6 @@ def __init__(self, settings):
self.declared_handlers.insert(-1, ("/developer/login", auth.DeveloperLoginHandler))
self.declared_handlers.insert(-1, ("/developer/quit", application.QuitHandler))

# google oauth key
self.oauth_key = tornado_settings["google_oauth"]["key"]

# Setup the Tornado Application
tornado.web.Application.__init__(self, self.declared_handlers, **settings)

Expand Down
5 changes: 0 additions & 5 deletions backend/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import os
import sys
import json
Expand All @@ -23,10 +22,6 @@
json_settings = json.load(json_settings_fh)
json_settings_fh.close()

google_key = json_settings["googleKey"]
google_secret = json_settings["googleSecret"]
redirect_uri = json_settings["redirectUri"]

elixir = json_settings["elixir"]

## Generated with base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
Expand Down
1 change: 0 additions & 1 deletion frontend/src/js/app.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
.config(["$routeProvider", "$locationProvider", "$httpProvider", function($routeProvider, $locationProvider, $httpProvider) {
$routeProvider
.when("/", { templateUrl: "static/templates/ng-templates/home.html" })
.when("/login", { templateUrl: "static/templates/ng-templates/login.html" })
.when("/profile", { templateUrl: "static/templates/ng-templates/profile.html" })
.when("/error", { templateUrl: "static/templates/ng-templates/error.html" })
.when("/security_warning", { templateUrl: "static/templates/ng-templates/security-warning.html" })
Expand Down
19 changes: 1 addition & 18 deletions frontend/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,6 @@
<!-- CSS -->
<link rel="stylesheet" href="/static/css/main.css?v=[[ version ]]" type="text/css" />

[% if develop %]
[% else %]
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-85976442-1', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics -->
[% endif %]
</head>
<!-- define angular controller -->
<body ng-controller="mainController as mainCtrl">
Expand All @@ -57,11 +44,7 @@
</ul>
</li>
<li class="dropdown" ng_if="mainCtrl.loggedIn == false">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Login <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/elixir/login?next={{ mainCtrl.url() }}" target="_self">Elixir AAI</a></li>
<li><a href="/login/?next={{ mainCtrl.url() }}" target="_self">Google (legacy)</a></li>
</ul>
<a href="/elixir/login?next={{ mainCtrl.url() }}" target="_self">Login</a>
</li>
</ul>
</div>
Expand Down
65 changes: 0 additions & 65 deletions frontend/templates/ng-templates/login.html

This file was deleted.

Loading