-
Notifications
You must be signed in to change notification settings - Fork 57
flask and python3 conversion #42
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
e33ff06
390bdb6
3633240
223175f
9ff9977
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,7 +125,7 @@ work) run the object code and to modify the work, including scripts to | |
control those activities. However, it does not include the work's | ||
System Libraries, or general-purpose tools or generally available free | ||
programs which are used unmodified in performing those activities but | ||
which are not part of the work. For example, Corresponding Source | ||
which are not part of the work. For theme, Corresponding Source | ||
|
||
includes interface definition files associated with source files for | ||
the work, and the source code for shared libraries and dynamically | ||
linked subprograms that the work is specifically designed to require, | ||
|
@@ -311,7 +311,7 @@ fixed term (regardless of how the transaction is characterized), the | |
Corresponding Source conveyed under this section must be accompanied | ||
by the Installation Information. But this requirement does not apply | ||
if neither you nor any third party retains the ability to install | ||
modified object code on the User Product (for example, the work has | ||
modified object code on the User Product (for theme, the work has | ||
been installed in ROM). | ||
|
||
The requirement to provide Installation Information does not include a | ||
|
@@ -449,7 +449,7 @@ Corresponding Source of the work from the predecessor in interest, if | |
the predecessor has it or can get it with reasonable efforts. | ||
|
||
You may not impose any further restrictions on the exercise of the | ||
rights granted or affirmed under this License. For example, you may | ||
rights granted or affirmed under this License. For theme, you may | ||
not impose a license fee, royalty, or other charge for exercise of | ||
rights granted under this License, and you may not initiate litigation | ||
(including a cross-claim or counterclaim in a lawsuit) alleging that | ||
|
@@ -532,7 +532,7 @@ otherwise) that contradict the conditions of this License, they do not | |
excuse you from the conditions of this License. If you cannot convey a | ||
covered work so as to satisfy simultaneously your obligations under this | ||
License and any other pertinent obligations, then as a consequence you may | ||
not convey it at all. For example, if you agree to terms that obligate you | ||
not convey it at all. For theme, if you agree to terms that obligate you | ||
to collect a royalty for further conveying from those to whom you convey | ||
the Program, the only way you could satisfy both those terms and this | ||
License would be to refrain entirely from conveying the Program. | ||
|
@@ -649,7 +649,7 @@ Also add information on how to contact you by electronic and paper mail. | |
|
||
If your software can interact with users remotely through a computer | ||
network, you should also make sure that it provides a way for users to | ||
get its source. For example, if your program is a web application, its | ||
get its source. For theme, if your program is a web application, its | ||
interface could display a "Source" link that leads users to an archive | ||
of the code. There are many ways you could offer source, and different | ||
solutions will be better for different programs; see section 13 for the | ||
|
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' |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,16 +18,16 @@ | |
# 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 | ||
# 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 | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,32 +18,42 @@ | |
# along with OAuth2 CKAN Extension. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import sqlalchemy as sa | ||
import ckan.model.meta as meta | ||
import logging | ||
|
||
from ckan.model.domain_object import DomainObject | ||
from sqlalchemy.ext.declarative import declarative_base | ||
|
||
UserToken = None | ||
log = logging.getLogger(__name__) | ||
|
||
|
||
Base = declarative_base() | ||
metadata = Base.metadata | ||
|
||
def init_db(model): | ||
|
||
global UserToken | ||
if UserToken is None: | ||
class UserToken(Base, DomainObject): | ||
__tablename__ = 'user_token' | ||
|
||
class _UserToken(model.DomainObject): | ||
def __init__(self, user_name, access_token, token_type, refresh_token, expires_in): | ||
self.user_name = user_name | ||
self.access_token = access_token | ||
self.token_type = token_type | ||
self.refresh_token = refresh_token | ||
self.expires_in = expires_in | ||
|
||
@classmethod | ||
def by_user_name(cls, user_name): | ||
return model.Session.query(cls).filter_by(user_name=user_name).first() | ||
@classmethod | ||
def by_user_name(cls, user_name): | ||
return meta.Session.query(cls).filter_by(user_name=user_name).first() | ||
|
||
UserToken = _UserToken | ||
|
||
user_token_table = sa.Table('user_token', model.meta.metadata, | ||
sa.Column('user_name', sa.types.UnicodeText, primary_key=True), | ||
sa.Column('access_token', sa.types.UnicodeText), | ||
sa.Column('token_type', sa.types.UnicodeText), | ||
sa.Column('refresh_token', sa.types.UnicodeText), | ||
sa.Column('expires_in', sa.types.UnicodeText) | ||
) | ||
user_name = sa.Column(sa.types.UnicodeText, primary_key=True) | ||
access_token = sa.Column(sa.types.UnicodeText) | ||
token_type = sa.Column(sa.types.UnicodeText) | ||
refresh_token = sa.Column(sa.types.UnicodeText) | ||
expires_in = sa.Column(sa.types.UnicodeText) | ||
|
||
# Create the table only if it does not exist | ||
user_token_table.create(checkfirst=True) | ||
|
||
model.meta.mapper(UserToken, user_token_table) | ||
|
||
|
||
|
||
# # Create the table only if it does not exist | ||
# user_token_table.create(checkfirst=True) | ||
|
||
# model.meta.mapper(UserToken, user_token_table) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,11 +19,11 @@ | |
# along with OAuth2 CKAN Extension. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
|
||
from __future__ import unicode_literals | ||
# from __future__ import unicode_literals | ||
|
||
|
||
import base64 | ||
import ckan.model as model | ||
import db | ||
from ckanext.oauth2.db import UserToken | ||
import json | ||
import logging | ||
from six.moves.urllib.parse import urljoin | ||
|
@@ -38,23 +38,24 @@ | |
|
||
import jwt | ||
|
||
import constants | ||
from .constants import * | ||
|
||
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): | ||
|
@@ -79,10 +80,8 @@ 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) | ||
self.redirect_uri = urljoin(urljoin(toolkit.config.get('ckan.site_url', 'http://localhost:5000'), toolkit.config.get('ckan.root_path')), REDIRECT_URL) | ||
|
||
# Init db | ||
db.init_db(model) | ||
|
||
missing = [key for key in REQUIRED_CONF if getattr(self, key, "") == ""] | ||
if missing: | ||
|
@@ -93,11 +92,12 @@ def __init__(self): | |
def challenge(self, came_from_url): | ||
# This function is called by the log in function when the user is not logged in | ||
state = generate_state(came_from_url) | ||
# log.debug(f'redirect uri: {self.redirect_uri}') | ||
|
||
oauth = OAuth2Session(self.client_id, redirect_uri=self.redirect_uri, scope=self.scope, state=state) | ||
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) | ||
|
@@ -111,39 +111,45 @@ 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'self.token_endpoint: {self.token_endpoint}') | ||
# log.debug(f'headers: {headers}') | ||
# log.debug(f'authorization_response: {toolkit.request.url}') | ||
# log.debug(f'client_secret: {self.client_secret}') | ||
|
||
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) | ||
# verify=self.verify_https | ||
# headers=headers, | ||
# log.debug(f'token: {token}') | ||
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: | ||
|
||
try: | ||
if self.legacy_idm: | ||
profile_response = requests.get(self.profile_api_url + '?access_token=%s' % token['access_token'], verify=self.verify_https) | ||
log.debug(f'profile response: {profile_response}') | ||
|
||
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) | ||
log.debug(f'profile response_: {profile_response}') | ||
|
||
|
||
except requests.exceptions.SSLError as e: | ||
# TODO search a better way to detect invalid certificates | ||
|
@@ -162,6 +168,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) | ||
|
@@ -214,18 +221,33 @@ 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 | ||
# toolkit.response.status = 302 | ||
# toolkit.response.location = came_from | ||
# return toolkit.redirect_to(came_from) | ||
# log.debug(f'come from: {came_from}') | ||
# 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) | ||
# log.debug(f'user_name: {user_name}') | ||
user_token = UserToken.by_user_name(user_name=user_name) | ||
if user_token: | ||
return { | ||
'access_token': user_token.access_token, | ||
|
@@ -235,22 +257,25 @@ 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 = UserToken.by_user_name(user_name=user_name) | ||
except AttributeError as e: | ||
user_token = None | ||
# log.debug(f'User_token: {user_token}') | ||
# Create the user if it does not exist | ||
if not user_token: | ||
user_token = db.UserToken() | ||
user_token.user_name = user_name | ||
# Save the new token | ||
user_token.access_token = token['access_token'] | ||
user_token.token_type = token['token_type'] | ||
user_token.refresh_token = token.get('refresh_token') | ||
access_token = token['access_token'] | ||
token_type = token['token_type'] | ||
refresh_token = token.get('refresh_token') | ||
if 'expires_in' in token: | ||
user_token.expires_in = token['expires_in'] | ||
expires_in = token['expires_in'] | ||
else: | ||
access_token = jwt.decode(user_token.access_token, verify=False) | ||
user_token.expires_in = access_token['exp'] - access_token['iat'] | ||
|
||
expires_in = access_token['exp'] - access_token['iat'] | ||
if not user_token: | ||
user_token = UserToken(user_name, access_token, token_type, refresh_token, expires_in) | ||
log.debug('user addedd') | ||
# log.debug(f'User_token: {user_token}') | ||
model.Session.add(user_token) | ||
model.Session.commit() | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of places where the word
example
is replaced bytheme
. Why?