diff --git a/ckanext/googleauth/plugin.py b/ckanext/googleauth/plugin.py
index 075158b..3f1adbe 100644
--- a/ckanext/googleauth/plugin.py
+++ b/ckanext/googleauth/plugin.py
@@ -1,44 +1,30 @@
-'''This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.'''
-
-
-
# coding=utf-8
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
from ckan.lib.plugins import DefaultTranslation
import json
+import logging
import uuid
+
+from google.oauth2 import id_token
+from google.auth.transport import requests
import pylons
import pylons.config as config
-import ckan.lib.helpers as helpers
-import requests
+import ckan.lib.helpers as h
import re
-
+log = logging.getLogger(__name__)
#get 'ckan.googleauth_clientid' from ini file
def get_clientid():
return config.get('ckan.googleauth_clientid', '')
+def get_loginuri():
+ site_url = config.get('ckan.site_url')
+ return '%s/user/login' % (site_url)
+
+
#get ckan.googleauth_hosted_domain from ini file
def get_hosted_domain():
return config.get('ckan.googleauth_hosted_domain', '')
@@ -71,55 +57,38 @@ class GoogleauthPlugin(plugins.SingletonPlugin, DefaultTranslation):
def update_config(self, config_):
toolkit.add_template_directory(config_, 'templates')
- toolkit.add_public_directory(config_, 'public')
- toolkit.add_resource('fanstatic', 'googleauth')
#declare new helper functions
def get_helpers(self):
return {'googleauth_get_clientid': get_clientid,
+ 'googleauth_get_loginuri': get_loginuri,
'googleauth_get_hosted_domain': get_hosted_domain}
- #verify email address within token
- def verify_email(self, token):
- res = requests.post('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token='+token, verify=True)
-
- if res.ok:
- is_email_verified=json.loads(res.content)
- if is_email_verified['email_verified'] == 'true':
- email_verified = is_email_verified['email']
- return email_verified
- else:
- raise GoogleAuthException(is_email_verified)
- else:
- raise GoogleAuthException(res)
-
-
-
#if exist returns ckan user
def get_ckanuser(self, user):
import ckan.model
- user_ckan = ckan.model.User.by_name(user)
+ user_ckan = ckan.model.User.by_name(user)
- if user_ckan:
- user_dict = toolkit.get_action('user_show')(data_dict={'id': user_ckan.id})
- return user_dict
- else:
- return None
+ if user_ckan:
+ user_dict = toolkit.get_action('user_show')(data_dict={'id': user_ckan.id})
+ return user_dict
+ else:
+ return None
#generates a strong password
def get_ckanpasswd(self):
- import datetime
- import random
+ import datetime
+ import random
- passwd = str(random.random())+ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")+str(uuid.uuid4().hex)
- passwd = re.sub(r"\s+", "", passwd, flags=re.UNICODE)
- return passwd
+ passwd = str(random.random())+ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")+str(uuid.uuid4().hex)
+ passwd = re.sub(r"\s+", "", passwd, flags=re.UNICODE)
+ return passwd
@@ -139,53 +108,93 @@ def _logout_user(self):
del pylons.session['ckanext-google-user']
if 'ckanext-google-email' in pylons.session:
del pylons.session['ckanext-google-email']
+ if 'ckanext-google-foo' in pylons.session:
+ del pylons.session['ckanext-google-foo']
pylons.session.save()
#at every access the email address is checked. if it is authorized ckan username is created and access is given
def login(self):
+ log.debug('login()')
+
+ # pylons.session['ckanext-google-foo'] = 'bar'
+ # pylons.session.save()
params = toolkit.request.params
- if 'id_token' in params:
- try:
- mail_verified = self.verify_email(params['id_token'])
- except GoogleAuthException, e:
- toolkit.abort(500)
+ if 'credential' in params:
+ log.debug('credential in params')
+ # https://developers.google.com/identity/gsi/web/reference/js-reference#CredentialResponse
+ # https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
+ id_info = id_token.verify_oauth2_token(
+ params['credential'], requests.Request(), get_clientid()
+ )
+ if id_info.get('hd', '') != get_hosted_domain():
+ log.debug('Hosted domain mismatch: aborting...')
+ toolkit.abort(500)
+
+ email = id_info['email']
+ log.debug('Email address: %s' % email)
+
+ user_account = email_to_ckan_user(email)
+ log.debug('User account: %s' % user_account)
- user_account = email_to_ckan_user(mail_verified)
+ user_ckan = self.get_ckanuser(user_account)
- user_ckan = self.get_ckanuser(user_account)
+ if not user_ckan:
+ log.debug('Creating CKAN user')
+ user_ckan = toolkit.get_action('user_create')(
+ context={'ignore_auth': True},
+ data_dict={'email': email,
+ 'name': user_account,
+ 'password': self.get_ckanpasswd()})
- if not user_ckan:
- user_ckan = toolkit.get_action('user_create')(
- context={'ignore_auth': True},
- data_dict={'email': mail_verified,
- 'name': user_account,
- 'password': self.get_ckanpasswd()})
+ pylons.session['ckanext-google-user'] = user_ckan['name']
+ pylons.session['ckanext-google-email'] = email
- pylons.session['ckanext-google-user'] = user_ckan['name']
- pylons.session['ckanext-google-email'] = mail_verified
+ #to revoke the Google token uncomment the code below
+ #pylons.session['ckanext-google-accesstoken'] = params['token']
- #to revoke the Google token uncomment the code below
- #pylons.session['ckanext-google-accesstoken'] = params['token']
- pylons.session.save()
+ log.debug('Saving pylons session... %r' % pylons.session)
+ pylons.session.save()
+ log.debug('Session type: %s' % pylons.session.type)
+ log.debug('Session dir: %s' % pylons.session.data_dir)
+ log.debug('Session id: %s' % pylons.session.id)
+ log.debug('Session use_cookies: %s' % pylons.session.use_cookies)
+ log.debug('Session timeout: %s' % pylons.session.timeout)
+ log.debug('Redirecting to dashboard')
+ h.redirect_to('/dashboard')
#if someone is logged in will be set the parameter c.user
def identify(self):
- user_ckan = pylons.session.get('ckanext-google-user')
- if user_ckan:
- toolkit.c.user = user_ckan
+ log.debug('identify()')
+ log.debug('Pylons session... %r' % pylons.session)
+ log.debug('Session type: %s' % pylons.session.type)
+ log.debug('Session dir: %s' % pylons.session.data_dir)
+ log.debug('Session id: %s' % pylons.session.id)
+ log.debug('Session use_cookies: %s' % pylons.session.use_cookies)
+ log.debug('Session timeout: %s' % pylons.session.timeout)
+ user_ckan = pylons.session.get('ckanext-google-user')
+ log.debug('CKAN User: %r' % user_ckan)
+ if user_ckan:
+ toolkit.c.user = user_ckan
def logout(self):
+ log.debug('logout()')
self._logout_user()
def abort(self, status_code=None, detail='', headers=None, comment=None):
+ log.debug('abort() status_code=%s' % status_code)
+
+ log.debug('Pylons session... %r' % pylons.session)
+
+ if status_code == 403 or status_code == 404:
+ return (status_code, detail, headers, comment)
self._logout_user()
return (status_code, detail, headers, comment)
diff --git a/ckanext/googleauth/public/.gitignore b/ckanext/googleauth/public/.gitignore
deleted file mode 100644
index e69de29..0000000
diff --git a/ckanext/googleauth/public/base/css/gbutton.css b/ckanext/googleauth/public/base/css/gbutton.css
deleted file mode 100644
index b231399..0000000
--- a/ckanext/googleauth/public/base/css/gbutton.css
+++ /dev/null
@@ -1,36 +0,0 @@
-#g-signin-button {
- display: inline-block;
- background: #4285f4;
- color: white;
- width: 190px;
- border-radius: 5px;
- white-space: nowrap;
-}
-
-#g-signin-button:hover {
- cursor: pointer;
-}
-
-span.label {
- font-weight: bold;
-}
-
-span.icon {
- background: url('/base/images/g7.png') transparent 50% no-repeat;
- display: inline-block;
- vertical-align: middle;
- width: 42px;
- height: 42px;
- /*border-right: #2265d4 1px solid;*/
-}
-
-span.button-text {
- display: inline-block;
- vertical-align: middle;
- padding-left: 32px;
- padding-right: 32px;
- font-size: 14px;
- font-weight: bold;
- /* Use the Roboto font that is loaded in the
*/
- font-family: 'Roboto', sans-serif;
-}
diff --git a/ckanext/googleauth/public/base/images/g7.png b/ckanext/googleauth/public/base/images/g7.png
deleted file mode 100644
index 77ba4a7..0000000
Binary files a/ckanext/googleauth/public/base/images/g7.png and /dev/null differ
diff --git a/ckanext/googleauth/public/base/js/googleauth.js b/ckanext/googleauth/public/base/js/googleauth.js
deleted file mode 100644
index e1c7515..0000000
--- a/ckanext/googleauth/public/base/js/googleauth.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/*This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.*/
-
-
-var googleUser = {};
-var cid = getMetaContent('google-signin-client_id');
-var hd = getMetaContent('google-signin-hosted_domain');
-var startApp = function() {
- gapi.load('auth2', function(){
- auth2 = gapi.auth2.init({
- client_id: cid,
- cookiepolicy: 'single_host_origin',
- hosted_domain: hd
- });
- var button = document.getElementById('g-signin-button');
- if (button) {
- attachSignin(button);
- }
- });
-};
-
-
-
-function attachSignin(element) {
- auth2.attachClickHandler(element, {},
- function(googleUser) {
-
- var profile = googleUser.getBasicProfile();
- var name = profile.getName();
- var email = profile.getEmail();
-
- var response = googleUser.getAuthResponse();
- var id_token = response['id_token'];
- var access_token = response['access_token'];
-
- $.ajax({
- type: 'POST',
- url:'/user/login',
- data: {name: name, email: email, id_token: id_token, token: access_token},
- success: function(res, status, xhr) {
- window.location.replace("/dashboard");
- },
- error: function(xhr, status, err) {
- alert("Login failure: " + err);
- }
- });
-
- }, function(error) {
-
-
- });
-
-}
-
-
-
-/*get content from meta tag*/
-function getMetaContent(propName) {
- var metas = document.getElementsByTagName('meta');
- for (i = 0; i < metas.length; i++) {
- if (metas[i].getAttribute("name") == propName) {
- return metas[i].getAttribute("content");
- }
- }
- return "";
-}
diff --git a/ckanext/googleauth/templates/base.html b/ckanext/googleauth/templates/base.html
index 838d0fa..0fafdcb 100644
--- a/ckanext/googleauth/templates/base.html
+++ b/ckanext/googleauth/templates/base.html
@@ -1,28 +1,6 @@
{% ckan_extends %}
-
-
-{% block styles %}
-
-
- {{ super() }}
-{% endblock %}
-
-
-{% block meta %}
-{% set ci=h.googleauth_get_clientid() %}
-{% set hd=h.googleauth_get_hosted_domain() %}
- {{ super() }}
-
-
-
-{% endblock %}
-
-
-
{% block scripts %}
{{ super() }}
-
-
-
+
{% endblock %}
diff --git a/ckanext/googleauth/templates/user/login.html b/ckanext/googleauth/templates/user/login.html
index 50bb07e..a2ca356 100644
--- a/ckanext/googleauth/templates/user/login.html
+++ b/ckanext/googleauth/templates/user/login.html
@@ -13,10 +13,11 @@
diff --git a/setup.py b/setup.py
index b17e73a..d43bc4f 100644
--- a/setup.py
+++ b/setup.py
@@ -59,7 +59,9 @@
# project is installed. For an analysis of "install_requires" vs pip's
# requirements files see:
# https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files
- install_requires=[],
+ install_requires=[
+ 'google-auth<=1.34.0',
+ ],
# If there are data files included in your packages that need to be
# installed, specify them here. If using Python 2.6 or less, then these