Skip to content

Commit

Permalink
Merge pull request #576 from NBISweden/develop
Browse files Browse the repository at this point in the history
Merge for v25
  • Loading branch information
viklund committed Jun 26, 2019
2 parents 24032e4 + 17f8252 commit 2e51da0
Show file tree
Hide file tree
Showing 31 changed files with 693 additions and 641 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
language: python
python:
- "3.6"
matrix:
include:
- python: 3.6
dist: bionic
- python: 3.7
dist: bionic
services:
- docker
before_install:
Expand Down
22 changes: 19 additions & 3 deletions backend/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@ class GetSchema(handlers.UnsafeHandler):
def get(self):
dataset = None
version = None
beacon = None
try:
url = self.get_argument('url')
match = re.match(".*/dataset/([^/]+)(/version/([^/]+))?", url)
if match:
dataset = match.group(1)
version = match.group(3)
beacon = re.match(".*/dataset/.*/beacon", url)
except tornado.web.MissingArgumentError:
pass

Expand Down Expand Up @@ -126,6 +128,21 @@ def get(self):
except db.DatasetVersionCurrent.DoesNotExist as e:
logging.error("Dataset does not exist: {}".format(e))

if beacon:
base = {"@context": "http://schema.org",
"@id": "https://swefreq.nbis.se/api/beacon-elixir/", # or maybe "se.nbis.swefreq" as in the beacon api?
"@type": "Beacon",
"dataset": [dataset_schema],
"dct:conformsTo": "https://bioschemas.org/specifications/drafts/Beacon/",
"name": "Swefreq Beacon",
"provider": base["provider"],
"supportedRefs": ["GRCh37"],
"description": "Beacon API Web Server based on the GA4GH Beacon API",
"version": "1.1.0", # beacon api version
"aggregator": False,
"url": "https://swefreq.nbis.se/api/beacon-elixir/"
}

self.finish(base)


Expand Down Expand Up @@ -307,7 +324,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 Expand Up @@ -522,7 +538,7 @@ def get(self, dataset):
))
query = peewee.prefetch(users, access)

self.finish({'data': _build_json_response(query, lambda u: u.access_pending_prefetch)})
self.finish({'data': _build_json_response(query, lambda u: u.access_pending)})


class DatasetUsersCurrent(handlers.AdminHandler):
Expand All @@ -537,7 +553,7 @@ def get(self, dataset):
))
query = peewee.prefetch(users, access)
self.finish({'data': _build_json_response(
query, lambda u: u.access_current_prefetch)})
query, lambda u: u.access_current)})


class UserDatasetAccess(handlers.SafeHandler):
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})
Loading

0 comments on commit 2e51da0

Please sign in to comment.