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

flask and python3 conversion #42

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions ckanext/oauth2/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-

import click

@click.group()
def oauth2():
"""Oauth2 management commands.
"""
pass
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it needed?



def get_commands():
return [oauth2]
2 changes: 1 addition & 1 deletion ckanext/oauth2/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
CAME_FROM_FIELD = 'came_from'
INITIAL_PAGE = '/dashboard'
INITIAL_PAGE = '/'
REDIRECT_URL = 'oauth2/callback'
6 changes: 2 additions & 4 deletions ckanext/oauth2/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with OAuth2 CKAN Extension. If not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import logging
import constants
from ckanext.oauth2 import constants

from ckan.common import session
import ckan.lib.helpers as helpers
import ckan.lib.base as base
import ckan.plugins.toolkit as toolkit
import oauth2
from ckanext.oauth2 import oauth2

from ckanext.oauth2.plugin import _get_previous_page

Expand Down
6 changes: 4 additions & 2 deletions ckanext/oauth2/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
# along with OAuth2 CKAN Extension. If not, see <http://www.gnu.org/licenses/>.

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base

UserToken = None

Base = declarative_base()
metadata = Base.metadata

UserToken = None
def init_db(model):

global UserToken
Expand Down
63 changes: 36 additions & 27 deletions ckanext/oauth2/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
# along with OAuth2 CKAN Extension. If not, see <http://www.gnu.org/licenses/>.


from __future__ import unicode_literals

import base64
import ckan.model as model
import db
from ckanext.oauth2.db import UserToken
import ckanext.oauth2.db as db
import json
import logging
from six.moves.urllib.parse import urljoin
Expand All @@ -38,23 +37,24 @@

import jwt

import constants
from .constants import CAME_FROM_FIELD, REDIRECT_URL
from flask import Flask, request, redirect, session, url_for, jsonify



log = logging.getLogger(__name__)


def generate_state(url):
return b64encode(bytes(json.dumps({constants.CAME_FROM_FIELD: url})))
return b64encode(bytes(json.dumps({CAME_FROM_FIELD: url}).encode()))


def get_came_from(state):
return json.loads(b64decode(state)).get(constants.CAME_FROM_FIELD, '/')
return json.loads(b64decode(state)).get(CAME_FROM_FIELD, '/')


REQUIRED_CONF = ("authorization_endpoint", "token_endpoint", "client_id", "client_secret", "profile_api_url", "profile_api_user_field", "profile_api_mail_field")


class OAuth2Helper(object):

def __init__(self):
Expand All @@ -79,10 +79,7 @@ def __init__(self):
self.profile_api_groupmembership_field = six.text_type(os.environ.get('CKAN_OAUTH2_PROFILE_API_GROUPMEMBERSHIP_FIELD', toolkit.config.get('ckan.oauth2.profile_api_groupmembership_field', ''))).strip()
self.sysadmin_group_name = six.text_type(os.environ.get('CKAN_OAUTH2_SYSADMIN_GROUP_NAME', toolkit.config.get('ckan.oauth2.sysadmin_group_name', ''))).strip()

self.redirect_uri = urljoin(urljoin(toolkit.config.get('ckan.site_url', 'http://localhost:5000'), toolkit.config.get('ckan.root_path')), constants.REDIRECT_URL)

# Init db
db.init_db(model)
self.redirect_uri = urljoin(urljoin(toolkit.config.get('ckan.site_url', 'http://localhost:5000'), toolkit.config.get('ckan.root_path')), REDIRECT_URL)

missing = [key for key in REQUIRED_CONF if getattr(self, key, "") == ""]
if missing:
Expand All @@ -97,7 +94,7 @@ def challenge(self, came_from_url):
auth_url, _ = oauth.authorization_url(self.authorization_endpoint)
log.debug('Challenge: Redirecting challenge to page {0}'.format(auth_url))
# CKAN 2.6 only supports bytes
return toolkit.redirect_to(auth_url.encode('utf-8'))
return toolkit.redirect_to(auth_url)#.encode('utf-8'))

def get_token(self):
oauth = OAuth2Session(self.client_id, redirect_uri=self.redirect_uri, scope=self.scope)
Expand All @@ -111,41 +108,40 @@ def get_token(self):
if self.legacy_idm:
# This is only required for Keyrock v6 and v5
headers['Authorization'] = 'Basic %s' % base64.urlsafe_b64encode(
'%s:%s' % (self.client_id, self.client_secret)
(f'{self.client_id}:{self.client_secret}').encode()
)

try:
log.debug(f'authorization_response: {toolkit.request.url}')
token = oauth.fetch_token(self.token_endpoint,
headers=headers,
client_id=self.client_id,
client_secret=self.client_secret,
authorization_response=toolkit.request.url,
verify=self.verify_https)
authorization_response=toolkit.request.url.replace('http:', 'https:', 1))
except requests.exceptions.SSLError as e:
# TODO search a better way to detect invalid certificates
if "verify failed" in six.text_type(e):
raise InsecureTransportError()
else:
raise

return token

def identify(self, token):

if self.jwt_enable:

log.debug('jwt_enabled')
access_token = bytes(token['access_token'])
user_data = jwt.decode(access_token, verify=False)
user = self.user_json(user_data)
else:

else:
try:
if self.legacy_idm:
profile_response = requests.get(self.profile_api_url + '?access_token=%s' % token['access_token'], verify=self.verify_https)
else:
oauth = OAuth2Session(self.client_id, token=token)
profile_response = oauth.get(self.profile_api_url, verify=self.verify_https)
profile_response = oauth.get(self.profile_api_url)

except requests.exceptions.SSLError as e:
log.debug('exception identify oauth2')
# TODO search a better way to detect invalid certificates
if "verify failed" in six.text_type(e):
raise InsecureTransportError()
Expand All @@ -162,6 +158,7 @@ def identify(self, token):
else:
user_data = profile_response.json()
user = self.user_json(user_data)
log.debug(f'user: {user}')

# Save the user in the database
model.Session.add(user)
Expand All @@ -171,6 +168,7 @@ def identify(self, token):
return user.name

def user_json(self, user_data):
log.debug(f'user_data: {user_data}')
email = user_data[self.profile_api_mail_field]
user_name = user_data[self.profile_api_user_field]

Expand Down Expand Up @@ -214,15 +212,24 @@ def remember(self, user_name):
rememberer = self._get_rememberer(environ)
identity = {'repoze.who.userid': user_name}
headers = rememberer.remember(environ, identity)
response = jsonify()
for header, value in headers:
toolkit.response.headers.add(header, value)
response.headers[header] = value
return response

def redirect_from_callback(self):
def redirect_from_callback(self, resp_remember):
'''Redirect to the callback URL after a successful authentication.'''
state = toolkit.request.params.get('state')
came_from = get_came_from(state)
toolkit.response.status = 302
toolkit.response.location = came_from

response = jsonify()
response.status_code = 302
for header, value in resp_remember.headers:
response.headers[header] = value
response.headers['location'] = came_from
response.autocorrect_location_header = False
return response


def get_stored_token(self, user_name):
user_token = db.UserToken.by_user_name(user_name=user_name)
Expand All @@ -235,8 +242,10 @@ def get_stored_token(self, user_name):
}

def update_token(self, user_name, token):

user_token = db.UserToken.by_user_name(user_name=user_name)
try:
user_token = db.UserToken.by_user_name(user_name=user_name)
except AttributeError as e:
user_token = None
# Create the user if it does not exist
if not user_token:
user_token = db.UserToken()
Expand Down
Loading